blob: 34fc791f3a617a0addc5e5d4f331809af6a71124 [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
Brad Bishopd7bf8c12018-02-25 22:55:05 -050012from oeqa.selftest.case import OESelftestTestCase
13from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer
14from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer
Patrick Williams45852732022-04-02 08:58:32 -050015from oeqa.core.decorator import OETestTag
Brad Bishopd7bf8c12018-02-25 22:55:05 -050016
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080017oldmetapath = None
18
19def setUpModule():
20 import bb.utils
21
22 global templayerdir
23 templayerdir = tempfile.mkdtemp(prefix='devtoolqa')
24 corecopydir = os.path.join(templayerdir, 'core-copy')
25 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
26 edited_layers = []
27
28 # We need to take a copy of the meta layer so we can modify it and not
29 # have any races against other tests that might be running in parallel
30 # however things like COREBASE mean that you can't just copy meta, you
31 # need the whole repository.
32 def bblayers_edit_cb(layerpath, canonical_layerpath):
33 global oldmetapath
34 if not canonical_layerpath.endswith('/'):
35 # This helps us match exactly when we're using this path later
36 canonical_layerpath += '/'
37 if not edited_layers and canonical_layerpath.endswith('/meta/'):
38 canonical_layerpath = os.path.realpath(canonical_layerpath) + '/'
39 edited_layers.append(layerpath)
40 oldmetapath = os.path.realpath(layerpath)
41 result = runCmd('git rev-parse --show-toplevel', cwd=canonical_layerpath)
42 oldreporoot = result.output.rstrip()
43 newmetapath = os.path.join(corecopydir, os.path.relpath(oldmetapath, oldreporoot))
44 runCmd('git clone %s %s' % (oldreporoot, corecopydir), cwd=templayerdir)
45 # Now we need to copy any modified files
46 # You might ask "why not just copy the entire tree instead of
47 # cloning and doing this?" - well, the problem with that is
48 # TMPDIR or an equally large subdirectory might exist
49 # under COREBASE and we don't want to copy that, so we have
50 # to be selective.
51 result = runCmd('git status --porcelain', cwd=oldreporoot)
52 for line in result.output.splitlines():
53 if line.startswith(' M ') or line.startswith('?? '):
54 relpth = line.split()[1]
55 pth = os.path.join(oldreporoot, relpth)
56 if pth.startswith(canonical_layerpath):
57 if relpth.endswith('/'):
58 destdir = os.path.join(corecopydir, relpth)
Andrew Geisslerc3d88e42020-10-02 09:45:00 -050059 # avoid race condition by not copying .pyc files YPBZ#13421,13803
Andrew Geisslerd1e89492021-02-12 15:35:20 -060060 shutil.copytree(pth, destdir, ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080061 else:
62 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
63 bb.utils.mkdirhier(destdir)
64 shutil.copy2(pth, destdir)
65 return newmetapath
66 else:
67 return layerpath
68 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
69
70def tearDownModule():
71 if oldmetapath:
72 edited_layers = []
73 def bblayers_edit_cb(layerpath, canonical_layerpath):
74 if not edited_layers and canonical_layerpath.endswith('/meta'):
75 edited_layers.append(layerpath)
76 return oldmetapath
77 else:
78 return layerpath
79 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
80 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
81 shutil.rmtree(templayerdir)
82
Andrew Geissler595f6302022-01-24 19:11:47 +000083class DevtoolTestCase(OESelftestTestCase):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080084
85 def setUp(self):
86 """Test case setup function"""
Andrew Geissler595f6302022-01-24 19:11:47 +000087 super(DevtoolTestCase, self).setUp()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080088 self.workspacedir = os.path.join(self.builddir, 'workspace')
89 self.assertTrue(not os.path.exists(self.workspacedir),
90 'This test cannot be run with a workspace directory '
91 'under the build directory')
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080092
93 def _check_src_repo(self, repo_dir):
94 """Check srctree git repository"""
95 self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')),
96 'git repository for external source tree not found')
97 result = runCmd('git status --porcelain', cwd=repo_dir)
98 self.assertEqual(result.output.strip(), "",
99 'Created git repo is not clean')
100 result = runCmd('git symbolic-ref HEAD', cwd=repo_dir)
101 self.assertEqual(result.output.strip(), "refs/heads/devtool",
102 'Wrong branch in git repo')
103
104 def _check_repo_status(self, repo_dir, expected_status):
105 """Check the worktree status of a repository"""
106 result = runCmd('git status . --porcelain',
107 cwd=repo_dir)
108 for line in result.output.splitlines():
109 for ind, (f_status, fn_re) in enumerate(expected_status):
110 if re.match(fn_re, line[3:]):
111 if f_status != line[:2]:
112 self.fail('Unexpected status in line: %s' % line)
113 expected_status.pop(ind)
114 break
115 else:
116 self.fail('Unexpected modified file in line: %s' % line)
117 if expected_status:
118 self.fail('Missing file changes: %s' % expected_status)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500119
120 def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
121 with open(recipefile, 'r') as f:
122 invar = None
123 invalue = None
Brad Bishop6dbb3162019-11-25 09:41:34 -0500124 inherits = set()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500125 for line in f:
126 var = None
127 if invar:
128 value = line.strip().strip('"')
129 if value.endswith('\\'):
130 invalue += ' ' + value[:-1].strip()
131 continue
132 else:
133 invalue += ' ' + value.strip()
134 var = invar
135 value = invalue
136 invar = None
137 elif '=' in line:
138 splitline = line.split('=', 1)
139 var = splitline[0].rstrip()
140 value = splitline[1].strip().strip('"')
141 if value.endswith('\\'):
142 invalue = value[:-1].strip()
143 invar = var
144 continue
145 elif line.startswith('inherit '):
Brad Bishop6dbb3162019-11-25 09:41:34 -0500146 inherits.update(line.split()[1:])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500147
148 if var and var in checkvars:
149 needvalue = checkvars.pop(var)
150 if needvalue is None:
151 self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value))
152 if isinstance(needvalue, set):
153 if var == 'LICENSE':
154 value = set(value.split(' & '))
155 else:
156 value = set(value.split())
157 self.assertEqual(value, needvalue, 'values for %s do not match' % var)
158
159
160 missingvars = {}
161 for var, value in checkvars.items():
162 if value is not None:
163 missingvars[var] = value
164 self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars)
165
166 for inherit in checkinherits:
167 self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
168
169 def _check_bbappend(self, testrecipe, recipefile, appenddir):
170 result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
171 resultlines = result.output.splitlines()
172 inrecipe = False
173 bbappends = []
174 bbappendfile = None
175 for line in resultlines:
176 if inrecipe:
177 if line.startswith(' '):
178 bbappends.append(line.strip())
179 else:
180 break
181 elif line == '%s:' % os.path.basename(recipefile):
182 inrecipe = True
183 self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
184 for bbappend in bbappends:
185 if bbappend.startswith(appenddir):
186 bbappendfile = bbappend
187 break
188 else:
189 self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
190 return bbappendfile
191
192 def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
193 create_temp_layer(templayerdir, templayername, priority, recipepathspec)
194 if addlayer:
195 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
196 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
197
198 def _process_ls_output(self, output):
199 """
200 Convert ls -l output to a format we can reasonably compare from one context
201 to another (e.g. from host to target)
202 """
203 filelist = []
204 for line in output.splitlines():
205 splitline = line.split()
206 if len(splitline) < 8:
207 self.fail('_process_ls_output: invalid output line: %s' % line)
208 # Remove trailing . on perms
209 splitline[0] = splitline[0].rstrip('.')
210 # Remove leading . on paths
211 splitline[-1] = splitline[-1].lstrip('.')
212 # Drop fields we don't want to compare
213 del splitline[7]
214 del splitline[6]
215 del splitline[5]
216 del splitline[4]
217 del splitline[1]
218 filelist.append(' '.join(splitline))
219 return filelist
220
Andrew Geissler615f2f12022-07-15 14:00:58 -0500221 def _check_diff(self, diffoutput, addlines, removelines):
222 """Check output from 'git diff' matches expectation"""
223 remaining_addlines = addlines[:]
224 remaining_removelines = removelines[:]
225 for line in diffoutput.splitlines():
226 if line.startswith('+++') or line.startswith('---'):
227 continue
228 elif line.startswith('+'):
229 matched = False
230 for item in addlines:
231 if re.match(item, line[1:].strip()):
232 matched = True
233 remaining_addlines.remove(item)
234 break
235 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
236 elif line.startswith('-'):
237 matched = False
238 for item in removelines:
239 if re.match(item, line[1:].strip()):
240 matched = True
241 remaining_removelines.remove(item)
242 break
243 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
244 if remaining_addlines:
245 self.fail('Expected added lines not found: %s' % remaining_addlines)
246 if remaining_removelines:
247 self.fail('Expected removed lines not found: %s' % remaining_removelines)
248
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500249
Andrew Geissler595f6302022-01-24 19:11:47 +0000250class DevtoolBase(DevtoolTestCase):
251
252 @classmethod
253 def setUpClass(cls):
254 super(DevtoolBase, cls).setUpClass()
255 bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
256 cls.original_sstate = bb_vars['SSTATE_DIR']
257 cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
258 cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
259 cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
260 % cls.original_sstate)
261
262 @classmethod
263 def tearDownClass(cls):
264 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
265 runCmd('rm -rf %s' % cls.devtool_sstate)
266 super(DevtoolBase, cls).tearDownClass()
267
268 def setUp(self):
269 """Test case setup function"""
270 super(DevtoolBase, self).setUp()
271 self.append_config(self.sstate_conf)
272
273
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500274class DevtoolTests(DevtoolBase):
275
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500276 def test_create_workspace(self):
277 # Check preconditions
278 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400279 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 -0400280 # remove conf/devtool.conf to avoid it corrupting tests
281 devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
282 self.track_for_cleanup(devtoolconf)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500283 # Try creating a workspace layer with a specific path
284 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
285 self.track_for_cleanup(tempdir)
286 result = runCmd('devtool create-workspace %s' % tempdir)
287 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
288 result = runCmd('bitbake-layers show-layers')
289 self.assertIn(tempdir, result.output)
290 # Try creating a workspace layer with the default path
291 self.track_for_cleanup(self.workspacedir)
292 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
293 result = runCmd('devtool create-workspace')
294 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
295 result = runCmd('bitbake-layers show-layers')
296 self.assertNotIn(tempdir, result.output)
297 self.assertIn(self.workspacedir, result.output)
298
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800299class DevtoolAddTests(DevtoolBase):
300
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500301 def test_devtool_add(self):
302 # Fetch source
303 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
304 self.track_for_cleanup(tempdir)
305 pn = 'pv'
306 pv = '1.5.3'
Andrew Geissler09209ee2020-12-13 08:44:15 -0600307 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500308 result = runCmd('wget %s' % url, cwd=tempdir)
309 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
310 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
311 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
312 # Test devtool add
313 self.track_for_cleanup(self.workspacedir)
314 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
315 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
316 result = runCmd('devtool add %s %s' % (pn, srcdir))
317 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
318 # Test devtool status
319 result = runCmd('devtool status')
320 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
321 self.assertIn(recipepath, result.output)
322 self.assertIn(srcdir, result.output)
323 # Test devtool find-recipe
324 result = runCmd('devtool -q find-recipe %s' % pn)
325 self.assertEqual(recipepath, result.output.strip())
326 # Test devtool edit-recipe
327 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
328 self.assertEqual('123 %s' % recipepath, result.output.strip())
329 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
330 bitbake('%s -c cleansstate' % pn)
331 # Test devtool build
332 result = runCmd('devtool build %s' % pn)
333 bb_vars = get_bb_vars(['D', 'bindir'], pn)
334 installdir = bb_vars['D']
335 self.assertTrue(installdir, 'Could not query installdir variable')
336 bindir = bb_vars['bindir']
337 self.assertTrue(bindir, 'Could not query bindir variable')
338 if bindir[0] == '/':
339 bindir = bindir[1:]
340 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
341
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500342 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800343 # We need dbus built so that DEPENDS recognition works
344 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500345 # Fetch source from a remote URL, but do it outside of devtool
346 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
347 self.track_for_cleanup(tempdir)
348 pn = 'dbus-wait'
349 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
350 # We choose an https:// git URL here to check rewriting the URL works
351 url = 'https://git.yoctoproject.org/git/dbus-wait'
352 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
353 # instead of the directory name
354 result = runCmd('git clone %s noname' % url, cwd=tempdir)
355 srcdir = os.path.join(tempdir, 'noname')
356 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
357 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
358 # Test devtool add
359 self.track_for_cleanup(self.workspacedir)
360 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
361 # Don't specify a name since we should be able to auto-detect it
362 result = runCmd('devtool add %s' % srcdir)
363 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
364 # Check the recipe name is correct
365 recipefile = get_bb_var('FILE', pn)
366 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
367 self.assertIn(recipefile, result.output)
368 # Test devtool status
369 result = runCmd('devtool status')
370 self.assertIn(pn, result.output)
371 self.assertIn(srcdir, result.output)
372 self.assertIn(recipefile, result.output)
373 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000374 checkvars['LICENSE'] = 'GPL-2.0-only'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500375 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
376 checkvars['S'] = '${WORKDIR}/git'
377 checkvars['PV'] = '0.1+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000378 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500379 checkvars['SRCREV'] = srcrev
380 checkvars['DEPENDS'] = set(['dbus'])
381 self._test_recipe_contents(recipefile, checkvars, [])
382
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500383 def test_devtool_add_library(self):
384 # Fetch source
385 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
386 self.track_for_cleanup(tempdir)
387 version = '1.1'
388 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
389 result = runCmd('wget %s' % url, cwd=tempdir)
390 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
391 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
392 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
393 # Test devtool add (and use -V so we test that too)
394 self.track_for_cleanup(self.workspacedir)
395 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
396 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
397 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
398 # Test devtool status
399 result = runCmd('devtool status')
400 self.assertIn('libftdi', result.output)
401 self.assertIn(srcdir, result.output)
402 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
403 bitbake('libftdi -c cleansstate')
404 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
405 # There's also the matter of it installing cmake files to a path we don't
406 # normally cover, which triggers the installed-vs-shipped QA test we have
407 # within do_package
408 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
409 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
410 with open(recipefile, 'a') as f:
Patrick Williams213cb262021-08-07 19:21:33 -0500411 f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500412 # We don't have the ability to pick up this dependency automatically yet...
413 f.write('\nDEPENDS += "libusb1"\n')
414 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
415 # Test devtool build
416 result = runCmd('devtool build libftdi')
417 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
418 staging_libdir = bb_vars['TESTLIBOUTPUT']
419 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
420 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)
421 # Test devtool reset
422 stampprefix = bb_vars['STAMP']
423 result = runCmd('devtool reset libftdi')
424 result = runCmd('devtool status')
425 self.assertNotIn('libftdi', result.output)
426 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
427 matches = glob.glob(stampprefix + '*')
428 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
429 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
430
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500431 def test_devtool_add_fetch(self):
432 # Fetch source
433 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
434 self.track_for_cleanup(tempdir)
435 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400436 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500437 testrecipe = 'python-markupsafe'
438 srcdir = os.path.join(tempdir, testrecipe)
439 # Test devtool add
440 self.track_for_cleanup(self.workspacedir)
441 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
442 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
443 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
444 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
445 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
446 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
447 # Test devtool status
448 result = runCmd('devtool status')
449 self.assertIn(testrecipe, result.output)
450 self.assertIn(srcdir, result.output)
451 # Check recipe
452 recipefile = get_bb_var('FILE', testrecipe)
453 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
454 checkvars = {}
455 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
456 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
457 self._test_recipe_contents(recipefile, checkvars, [])
458 # Try with version specified
459 result = runCmd('devtool reset -n %s' % testrecipe)
460 shutil.rmtree(srcdir)
461 fakever = '1.9'
462 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
463 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
464 # Test devtool status
465 result = runCmd('devtool status')
466 self.assertIn(testrecipe, result.output)
467 self.assertIn(srcdir, result.output)
468 # Check recipe
469 recipefile = get_bb_var('FILE', testrecipe)
470 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
471 checkvars = {}
472 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
473 checkvars['SRC_URI'] = url
474 self._test_recipe_contents(recipefile, checkvars, [])
Andrew Geissler615f2f12022-07-15 14:00:58 -0500475
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500476 def test_devtool_add_fetch_git(self):
477 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
478 self.track_for_cleanup(tempdir)
479 url = 'gitsm://git.yoctoproject.org/mraa'
Andrew Geissler595f6302022-01-24 19:11:47 +0000480 url_branch = '%s;branch=master' % url
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500481 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
482 testrecipe = 'mraa'
483 srcdir = os.path.join(tempdir, testrecipe)
484 # Test devtool add
485 self.track_for_cleanup(self.workspacedir)
486 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
487 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
488 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
489 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
490 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
491 # Test devtool status
492 result = runCmd('devtool status')
493 self.assertIn(testrecipe, result.output)
494 self.assertIn(srcdir, result.output)
495 # Check recipe
496 recipefile = get_bb_var('FILE', testrecipe)
497 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
498 checkvars = {}
499 checkvars['S'] = '${WORKDIR}/git'
500 checkvars['PV'] = '1.0+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000501 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500502 checkvars['SRCREV'] = '${AUTOREV}'
503 self._test_recipe_contents(recipefile, checkvars, [])
504 # Try with revision and version specified
505 result = runCmd('devtool reset -n %s' % testrecipe)
506 shutil.rmtree(srcdir)
507 url_rev = '%s;rev=%s' % (url, checkrev)
508 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
509 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
510 # Test devtool status
511 result = runCmd('devtool status')
512 self.assertIn(testrecipe, result.output)
513 self.assertIn(srcdir, result.output)
514 # Check recipe
515 recipefile = get_bb_var('FILE', testrecipe)
516 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
517 checkvars = {}
518 checkvars['S'] = '${WORKDIR}/git'
519 checkvars['PV'] = '1.5+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000520 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500521 checkvars['SRCREV'] = checkrev
522 self._test_recipe_contents(recipefile, checkvars, [])
523
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500524 def test_devtool_add_fetch_simple(self):
525 # Fetch source from a remote URL, auto-detecting name
526 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
527 self.track_for_cleanup(tempdir)
528 testver = '1.6.0'
529 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
530 testrecipe = 'pv'
531 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
532 # Test devtool add
533 self.track_for_cleanup(self.workspacedir)
534 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
535 result = runCmd('devtool add %s' % url)
536 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
537 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
538 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
539 # Test devtool status
540 result = runCmd('devtool status')
541 self.assertIn(testrecipe, result.output)
542 self.assertIn(srcdir, result.output)
543 # Check recipe
544 recipefile = get_bb_var('FILE', testrecipe)
545 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
546 checkvars = {}
547 checkvars['S'] = None
548 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
549 self._test_recipe_contents(recipefile, checkvars, [])
550
Andrew Geissler82c905d2020-04-13 13:39:40 -0500551 def test_devtool_add_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600552 collections = get_bb_var('BBFILE_COLLECTIONS').split()
553 if "openembedded-layer" not in collections:
554 self.skipTest("Test needs meta-oe for nodejs")
555
Andrew Geissler82c905d2020-04-13 13:39:40 -0500556 pn = 'savoirfairelinux-node-server-example'
557 pv = '1.0.0'
558 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
559 # Test devtool add
560 self.track_for_cleanup(self.workspacedir)
561 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
562 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
563 result = runCmd('devtool add \'%s\'' % url)
564 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
565 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
566 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
567 # Test devtool status
568 result = runCmd('devtool status')
569 self.assertIn(pn, result.output)
570 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
571 bitbake('%s -c cleansstate' % pn)
572 # Test devtool build
573 result = runCmd('devtool build %s' % pn)
574
Andrew Geissler615f2f12022-07-15 14:00:58 -0500575 def test_devtool_add_python_egg_requires(self):
576 # Fetch source
577 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
578 self.track_for_cleanup(tempdir)
579 testver = '0.14.0'
580 url = 'https://files.pythonhosted.org/packages/e9/9e/25d59f5043cf763833b2581c8027fa92342c4cf8ee523b498ecdf460c16d/uvicorn-%s.tar.gz' % testver
581 testrecipe = 'python3-uvicorn'
582 srcdir = os.path.join(tempdir, testrecipe)
583 # Test devtool add
584 self.track_for_cleanup(self.workspacedir)
585 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
586 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
587
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800588class DevtoolModifyTests(DevtoolBase):
589
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500590 def test_devtool_modify(self):
591 import oe.path
592
593 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
594 self.track_for_cleanup(tempdir)
595 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500596 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400597 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500598 result = runCmd('devtool modify mdadm -x %s' % tempdir)
599 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
600 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
601 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
602 self.assertTrue(matches, 'bbappend not created %s' % result.output)
603
604 # Test devtool status
605 result = runCmd('devtool status')
606 self.assertIn('mdadm', result.output)
607 self.assertIn(tempdir, result.output)
608 self._check_src_repo(tempdir)
609
610 bitbake('mdadm -C unpack')
611
612 def check_line(checkfile, expected, message, present=True):
613 # Check for $expected, on a line on its own, in checkfile.
614 with open(checkfile, 'r') as f:
615 if present:
616 self.assertIn(expected + '\n', f, message)
617 else:
618 self.assertNotIn(expected + '\n', f, message)
619
620 modfile = os.path.join(tempdir, 'mdadm.8.in')
621 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
622 pkgd = bb_vars['PKGD']
623 self.assertTrue(pkgd, 'Could not query PKGD variable')
624 mandir = bb_vars['mandir']
625 self.assertTrue(mandir, 'Could not query mandir variable')
626 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
627
628 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
629 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
630
631 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
632 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
633
634 bitbake('mdadm -c package')
635 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
636
637 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
638 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
639
640 bitbake('mdadm -c package')
641 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
642
643 result = runCmd('devtool reset mdadm')
644 result = runCmd('devtool status')
645 self.assertNotIn('mdadm', result.output)
646
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500647 def test_devtool_buildclean(self):
648 def assertFile(path, *paths):
649 f = os.path.join(path, *paths)
650 self.assertExists(f)
651 def assertNoFile(path, *paths):
652 f = os.path.join(path, *paths)
653 self.assertNotExists(f)
654
655 # Clean up anything in the workdir/sysroot/sstate cache
656 bitbake('mdadm m4 -c cleansstate')
657 # Try modifying a recipe
658 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
659 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
660 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
661 self.track_for_cleanup(tempdir_mdadm)
662 self.track_for_cleanup(tempdir_m4)
663 self.track_for_cleanup(builddir_m4)
664 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500665 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400666 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500667 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
668 try:
669 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
670 runCmd('devtool modify m4 -x %s' % tempdir_m4)
671 assertNoFile(tempdir_mdadm, 'mdadm')
672 assertNoFile(builddir_m4, 'src/m4')
673 result = bitbake('m4 -e')
674 result = bitbake('mdadm m4 -c compile')
675 self.assertEqual(result.status, 0)
676 assertFile(tempdir_mdadm, 'mdadm')
677 assertFile(builddir_m4, 'src/m4')
678 # Check that buildclean task exists and does call make clean
679 bitbake('mdadm m4 -c buildclean')
680 assertNoFile(tempdir_mdadm, 'mdadm')
681 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400682 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500683 bitbake('mdadm m4 -c compile')
684 assertFile(tempdir_mdadm, 'mdadm')
685 assertFile(builddir_m4, 'src/m4')
686 bitbake('mdadm m4 -c clean')
687 # Check that buildclean task is run before clean for B == S
688 assertNoFile(tempdir_mdadm, 'mdadm')
689 # Check that buildclean task is not run before clean for B != S
690 assertFile(builddir_m4, 'src/m4')
691 finally:
692 self.delete_recipeinc('m4')
693
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500694 def test_devtool_modify_invalid(self):
695 # Try modifying some recipes
696 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
697 self.track_for_cleanup(tempdir)
698 self.track_for_cleanup(self.workspacedir)
699 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
700
Andrew Geissler5199d832021-09-24 16:47:35 -0500701 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500702 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
703 result = runCmd('bitbake-layers show-recipes gcc-source*')
704 for line in result.output.splitlines():
705 # just match those lines that contain a real target
706 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
707 if m:
708 testrecipes.append(m.group('recipe'))
709 for testrecipe in testrecipes:
710 # Check it's a valid recipe
711 bitbake('%s -e' % testrecipe)
712 # devtool extract should fail
713 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
714 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
715 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
716 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
717 # devtool modify should fail
718 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
719 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
720 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
721
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500722 def test_devtool_modify_native(self):
723 # Check preconditions
724 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
725 # Try modifying some recipes
726 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
727 self.track_for_cleanup(tempdir)
728 self.track_for_cleanup(self.workspacedir)
729 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
730
731 bbclassextended = False
732 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500733 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500734 for testrecipe in testrecipes:
735 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
736 if not bbclassextended:
737 bbclassextended = checkextend
738 if not inheritnative:
739 inheritnative = not checkextend
740 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
741 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
742 result = runCmd('devtool build %s' % testrecipe)
743 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
744 result = runCmd('devtool reset %s' % testrecipe)
745 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
746
747 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
748 self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
Andrew Geissler615f2f12022-07-15 14:00:58 -0500749
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600750 def test_devtool_modify_localfiles_only(self):
751 # Check preconditions
752 testrecipe = 'base-files'
753 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
754 foundlocalonly = False
755 correct_symlink = False
756 for item in src_uri:
757 if item.startswith('file://'):
758 if '.patch' not in item:
759 foundlocalonly = True
760 else:
761 foundlocalonly = False
762 break
763 self.assertTrue(foundlocalonly, 'This test expects the %s recipe to fetch local files only and it seems that it no longer does' % testrecipe)
764 # Clean up anything in the workdir/sysroot/sstate cache
765 bitbake('%s -c cleansstate' % testrecipe)
766 # Try modifying a recipe
767 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
768 self.track_for_cleanup(tempdir)
769 self.track_for_cleanup(self.workspacedir)
770 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
771 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
772 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
773 srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
774 srclink = os.path.join(tempdir, 'share/dot.bashrc')
775 self.assertExists(srcfile, 'Extracted source could not be found')
776 if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
777 correct_symlink = True
778 self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500779
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600780 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
781 self.assertTrue(matches, 'bbappend not created')
782 # Test devtool status
783 result = runCmd('devtool status')
784 self.assertIn(testrecipe, result.output)
785 self.assertIn(tempdir, result.output)
786 # Try building
787 bitbake(testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500788
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500789 def test_devtool_modify_git(self):
790 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400791 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500792 src_uri = get_bb_var('SRC_URI', testrecipe)
793 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
794 # Clean up anything in the workdir/sysroot/sstate cache
795 bitbake('%s -c cleansstate' % testrecipe)
796 # Try modifying a recipe
797 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
798 self.track_for_cleanup(tempdir)
799 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500800 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400801 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500802 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400803 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500804 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 -0400805 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500806 self.assertTrue(matches, 'bbappend not created')
807 # Test devtool status
808 result = runCmd('devtool status')
809 self.assertIn(testrecipe, result.output)
810 self.assertIn(tempdir, result.output)
811 # Check git repo
812 self._check_src_repo(tempdir)
813 # Try building
814 bitbake(testrecipe)
815
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500816 def test_devtool_modify_localfiles(self):
817 # Check preconditions
818 testrecipe = 'lighttpd'
819 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
820 foundlocal = False
821 for item in src_uri:
822 if item.startswith('file://') and '.patch' not in item:
823 foundlocal = True
824 break
825 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
826 # Clean up anything in the workdir/sysroot/sstate cache
827 bitbake('%s -c cleansstate' % testrecipe)
828 # Try modifying a recipe
829 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
830 self.track_for_cleanup(tempdir)
831 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500832 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400833 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500834 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
835 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
836 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
837 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
838 self.assertTrue(matches, 'bbappend not created')
839 # Test devtool status
840 result = runCmd('devtool status')
841 self.assertIn(testrecipe, result.output)
842 self.assertIn(tempdir, result.output)
843 # Try building
844 bitbake(testrecipe)
845
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500846 def test_devtool_modify_virtual(self):
847 # Try modifying a virtual recipe
848 virtrecipe = 'virtual/make'
849 realrecipe = 'make'
850 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
851 self.track_for_cleanup(tempdir)
852 self.track_for_cleanup(self.workspacedir)
853 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
854 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
855 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
856 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
857 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
858 self.assertTrue(matches, 'bbappend not created %s' % result.output)
859 # Test devtool status
860 result = runCmd('devtool status')
861 self.assertNotIn(virtrecipe, result.output)
862 self.assertIn(realrecipe, result.output)
863 # Check git repo
864 self._check_src_repo(tempdir)
865 # This is probably sufficient
866
Andrew Geisslerf0343792020-11-18 10:42:21 -0600867 def test_devtool_modify_overrides(self):
868 # Try modifying a recipe with patches in overrides
869 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
870 self.track_for_cleanup(tempdir)
871 self.track_for_cleanup(self.workspacedir)
872 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
873 result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
874
875 self._check_src_repo(tempdir)
876 source = os.path.join(tempdir, "source")
877 def check(branch, expected):
878 runCmd('git -C %s checkout %s' % (tempdir, branch))
879 with open(source, "rt") as f:
880 content = f.read()
881 self.assertEquals(content, expected)
882 check('devtool', 'This is a test for something\n')
883 check('devtool-no-overrides', 'This is a test for something\n')
884 check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
885 check('devtool-override-qemux86', 'This is a test for qemux86\n')
886
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800887class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500888
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500889 def test_devtool_update_recipe(self):
890 # Check preconditions
891 testrecipe = 'minicom'
892 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
893 recipefile = bb_vars['FILE']
894 src_uri = bb_vars['SRC_URI']
895 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
896 self._check_repo_status(os.path.dirname(recipefile), [])
897 # First, modify a recipe
898 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
899 self.track_for_cleanup(tempdir)
900 self.track_for_cleanup(self.workspacedir)
901 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
902 # (don't bother with cleaning the recipe on teardown, we won't be building it)
903 # We don't use -x here so that we test the behaviour of devtool modify without it
904 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
905 # Check git repo
906 self._check_src_repo(tempdir)
907 # Add a couple of commits
908 # FIXME: this only tests adding, need to also test update and remove
909 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
910 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
911 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
912 result = runCmd('git add devtool-new-file', cwd=tempdir)
913 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
914 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
915 result = runCmd('devtool update-recipe %s' % testrecipe)
916 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
917 ('??', '.*/0001-Change-the-README.patch$'),
918 ('??', '.*/0002-Add-a-new-file.patch$')]
919 self._check_repo_status(os.path.dirname(recipefile), expected_status)
920
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500921 def test_devtool_update_recipe_git(self):
922 # Check preconditions
923 testrecipe = 'mtd-utils'
924 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
925 recipefile = bb_vars['FILE']
926 src_uri = bb_vars['SRC_URI']
927 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
928 patches = []
929 for entry in src_uri.split():
930 if entry.startswith('file://') and entry.endswith('.patch'):
931 patches.append(entry[7:].split(';')[0])
932 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
933 self._check_repo_status(os.path.dirname(recipefile), [])
934 # First, modify a recipe
935 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
936 self.track_for_cleanup(tempdir)
937 self.track_for_cleanup(self.workspacedir)
938 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
939 # (don't bother with cleaning the recipe on teardown, we won't be building it)
940 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
941 # Check git repo
942 self._check_src_repo(tempdir)
943 # Add a couple of commits
944 # FIXME: this only tests adding, need to also test update and remove
945 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
946 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
947 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
948 result = runCmd('git add devtool-new-file', cwd=tempdir)
949 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
950 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
951 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
952 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
953 [(' D', '.*/%s$' % patch) for patch in patches]
954 self._check_repo_status(os.path.dirname(recipefile), expected_status)
955
956 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +0000957 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"']
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500958 srcurilines = src_uri.split()
959 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
960 srcurilines.append('"')
961 removelines = ['SRCREV = ".*"'] + srcurilines
Andrew Geissler615f2f12022-07-15 14:00:58 -0500962 self._check_diff(result.output, addlines, removelines)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500963 # Now try with auto mode
964 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
965 result = runCmd('devtool update-recipe %s' % testrecipe)
966 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
967 topleveldir = result.output.strip()
968 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
969 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
970 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
971 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
972 self._check_repo_status(os.path.dirname(recipefile), expected_status)
973
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500974 def test_devtool_update_recipe_append(self):
975 # Check preconditions
976 testrecipe = 'mdadm'
977 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
978 recipefile = bb_vars['FILE']
979 src_uri = bb_vars['SRC_URI']
980 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
981 self._check_repo_status(os.path.dirname(recipefile), [])
982 # First, modify a recipe
983 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
984 tempsrcdir = os.path.join(tempdir, 'source')
985 templayerdir = os.path.join(tempdir, 'layer')
986 self.track_for_cleanup(tempdir)
987 self.track_for_cleanup(self.workspacedir)
988 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
989 # (don't bother with cleaning the recipe on teardown, we won't be building it)
990 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
991 # Check git repo
992 self._check_src_repo(tempsrcdir)
993 # Add a commit
994 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
995 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
996 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
997 # Create a temporary layer and add it to bblayers.conf
998 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
999 # Create the bbappend
1000 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1001 self.assertNotIn('WARNING:', result.output)
1002 # Check recipe is still clean
1003 self._check_repo_status(os.path.dirname(recipefile), [])
1004 # Check bbappend was created
1005 splitpath = os.path.dirname(recipefile).split(os.sep)
1006 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1007 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1008 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
1009 self.assertExists(patchfile, 'Patch file not created')
1010
1011 # Check bbappend contents
Patrick Williams213cb262021-08-07 19:21:33 -05001012 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001013 '\n',
1014 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
1015 '\n']
1016 with open(bbappendfile, 'r') as f:
1017 self.assertEqual(expectedlines, f.readlines())
1018
1019 # Check we can run it again and bbappend isn't modified
1020 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1021 with open(bbappendfile, 'r') as f:
1022 self.assertEqual(expectedlines, f.readlines())
1023 # Drop new commit and check patch gets deleted
1024 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1025 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1026 self.assertNotExists(patchfile, 'Patch file not deleted')
Patrick Williams213cb262021-08-07 19:21:33 -05001027 expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001028 '\n']
1029 with open(bbappendfile, 'r') as f:
1030 self.assertEqual(expectedlines2, f.readlines())
1031 # Put commit back and check we can run it if layer isn't in bblayers.conf
1032 os.remove(bbappendfile)
1033 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1034 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1035 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1036 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1037 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
1038 with open(bbappendfile, 'r') as f:
1039 self.assertEqual(expectedlines, f.readlines())
1040 # Deleting isn't expected to work under these circumstances
1041
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001042 def test_devtool_update_recipe_append_git(self):
1043 # Check preconditions
1044 testrecipe = 'mtd-utils'
1045 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1046 recipefile = bb_vars['FILE']
1047 src_uri = bb_vars['SRC_URI']
1048 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1049 for entry in src_uri.split():
1050 if entry.startswith('git://'):
1051 git_uri = entry
1052 break
1053 self._check_repo_status(os.path.dirname(recipefile), [])
1054 # First, modify a recipe
1055 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1056 tempsrcdir = os.path.join(tempdir, 'source')
1057 templayerdir = os.path.join(tempdir, 'layer')
1058 self.track_for_cleanup(tempdir)
1059 self.track_for_cleanup(self.workspacedir)
1060 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1061 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1062 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1063 # Check git repo
1064 self._check_src_repo(tempsrcdir)
1065 # Add a commit
1066 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
1067 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1068 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1069 # Create a temporary layer
1070 os.makedirs(os.path.join(templayerdir, 'conf'))
1071 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
1072 f.write('BBPATH .= ":${LAYERDIR}"\n')
1073 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
1074 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
1075 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
1076 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
1077 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Brad Bishop316dfdd2018-06-25 12:45:53 -04001078 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "${LAYERSERIES_COMPAT_core}"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001079 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
1080 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
1081 # Create the bbappend
1082 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1083 self.assertNotIn('WARNING:', result.output)
1084 # Check recipe is still clean
1085 self._check_repo_status(os.path.dirname(recipefile), [])
1086 # Check bbappend was created
1087 splitpath = os.path.dirname(recipefile).split(os.sep)
1088 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1089 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1090 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1091
1092 # Check bbappend contents
1093 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1094 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1095 '\n',
1096 'SRC_URI = "%s"\n' % git_uri,
1097 '\n'])
1098 with open(bbappendfile, 'r') as f:
1099 self.assertEqual(expectedlines, set(f.readlines()))
1100
1101 # Check we can run it again and bbappend isn't modified
1102 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1103 with open(bbappendfile, 'r') as f:
1104 self.assertEqual(expectedlines, set(f.readlines()))
1105 # Drop new commit and check SRCREV changes
1106 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1107 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1108 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1109 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1110 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1111 '\n',
1112 'SRC_URI = "%s"\n' % git_uri,
1113 '\n'])
1114 with open(bbappendfile, 'r') as f:
1115 self.assertEqual(expectedlines, set(f.readlines()))
1116 # Put commit back and check we can run it if layer isn't in bblayers.conf
1117 os.remove(bbappendfile)
1118 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1119 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1120 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1121 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1122 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1123 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1124 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1125 '\n',
1126 'SRC_URI = "%s"\n' % git_uri,
1127 '\n'])
1128 with open(bbappendfile, 'r') as f:
1129 self.assertEqual(expectedlines, set(f.readlines()))
1130 # Deleting isn't expected to work under these circumstances
1131
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001132 def test_devtool_update_recipe_local_files(self):
1133 """Check that local source files are copied over instead of patched"""
1134 testrecipe = 'makedevs'
1135 recipefile = get_bb_var('FILE', testrecipe)
1136 # Setup srctree for modifying the recipe
1137 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1138 self.track_for_cleanup(tempdir)
1139 self.track_for_cleanup(self.workspacedir)
1140 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1141 # (don't bother with cleaning the recipe on teardown, we won't be
1142 # building it)
1143 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1144 # Check git repo
1145 self._check_src_repo(tempdir)
1146 # Try building just to ensure we haven't broken that
1147 bitbake("%s" % testrecipe)
1148 # Edit / commit local source
1149 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1150 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1151 runCmd('echo "Bar" > new-file', cwd=tempdir)
1152 runCmd('git add new-file', cwd=tempdir)
1153 runCmd('git commit -m "Add new file"', cwd=tempdir)
1154 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1155 os.path.dirname(recipefile))
1156 runCmd('devtool update-recipe %s' % testrecipe)
1157 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1158 (' M', '.*/makedevs/makedevs.c$'),
1159 ('??', '.*/makedevs/new-local$'),
1160 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1161 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1162
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001163 def test_devtool_update_recipe_local_files_2(self):
1164 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001165 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001166 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001167 recipedir = os.path.dirname(recipefile)
1168 result = runCmd('git status --porcelain .', cwd=recipedir)
1169 if result.output.strip():
1170 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001171 # Setup srctree for modifying the recipe
1172 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1173 self.track_for_cleanup(tempdir)
1174 self.track_for_cleanup(self.workspacedir)
1175 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1176 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1177 # Check git repo
1178 self._check_src_repo(tempdir)
1179 # Add oe-local-files to Git
1180 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1181 runCmd('git add oe-local-files', cwd=tempdir)
1182 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1183 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001184 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001185 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001186 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001187 runCmd('git commit -m"Remove file"', cwd=tempdir)
1188 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1189 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1190 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1191 runCmd('echo "Gar" > new-file', cwd=tempdir)
1192 runCmd('git add new-file', cwd=tempdir)
1193 runCmd('git commit -m "Add new file"', cwd=tempdir)
1194 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1195 os.path.dirname(recipefile))
1196 # Checkout unmodified file to working copy -> devtool should still pick
1197 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001198 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001199 runCmd('devtool update-recipe %s' % testrecipe)
1200 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001201 (' M', '.*/file1$'),
1202 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001203 ('??', '.*/new-local$'),
1204 ('??', '.*/0001-Add-new-file.patch$')]
1205 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1206
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001207 def test_devtool_update_recipe_with_gitignore(self):
1208 # First, modify the recipe
1209 testrecipe = 'devtool-test-ignored'
1210 bb_vars = get_bb_vars(['FILE'], testrecipe)
1211 recipefile = bb_vars['FILE']
1212 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1213 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
1214 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1215 self.track_for_cleanup(tempdir)
1216 self.track_for_cleanup(self.workspacedir)
1217 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1218 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1219 result = runCmd('devtool modify %s' % testrecipe)
1220 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1221 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1222 # Check recipe got changed as expected
1223 with open(newpatchfile, 'r') as f:
1224 desiredlines = f.readlines()
1225 with open(patchfile, 'r') as f:
1226 newlines = f.readlines()
1227 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1228 # which changes the metadata subject which is added into the patch, but keep
1229 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1230 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1231 self.assertEqual(desiredlines[5:], newlines[5:])
1232
1233 def test_devtool_update_recipe_long_filename(self):
1234 # First, modify the recipe
1235 testrecipe = 'devtool-test-long-filename'
1236 bb_vars = get_bb_vars(['FILE'], testrecipe)
1237 recipefile = bb_vars['FILE']
1238 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1239 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1240 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1241 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1242 self.track_for_cleanup(tempdir)
1243 self.track_for_cleanup(self.workspacedir)
1244 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1245 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1246 result = runCmd('devtool modify %s' % testrecipe)
1247 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1248 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1249 # Check recipe got changed as expected
1250 with open(newpatchfile, 'r') as f:
1251 desiredlines = f.readlines()
1252 with open(patchfile, 'r') as f:
1253 newlines = f.readlines()
1254 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1255 # which changes the metadata subject which is added into the patch, but keep
1256 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1257 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1258 self.assertEqual(desiredlines[5:], newlines[5:])
1259
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001260 def test_devtool_update_recipe_local_files_3(self):
1261 # First, modify the recipe
1262 testrecipe = 'devtool-test-localonly'
1263 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1264 recipefile = bb_vars['FILE']
1265 src_uri = bb_vars['SRC_URI']
1266 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1267 self.track_for_cleanup(tempdir)
1268 self.track_for_cleanup(self.workspacedir)
1269 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1270 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1271 result = runCmd('devtool modify %s' % testrecipe)
1272 # Modify one file
1273 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1274 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1275 result = runCmd('devtool update-recipe %s' % testrecipe)
1276 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1277 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1278
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001279 def test_devtool_update_recipe_local_patch_gz(self):
1280 # First, modify the recipe
1281 testrecipe = 'devtool-test-patch-gz'
1282 if get_bb_var('DISTRO') == 'poky-tiny':
1283 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1284 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1285 recipefile = bb_vars['FILE']
1286 src_uri = bb_vars['SRC_URI']
1287 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1288 self.track_for_cleanup(tempdir)
1289 self.track_for_cleanup(self.workspacedir)
1290 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1291 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1292 result = runCmd('devtool modify %s' % testrecipe)
1293 # Modify one file
1294 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1295 runCmd('echo "Another line" >> README', cwd=srctree)
1296 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1297 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1298 result = runCmd('devtool update-recipe %s' % testrecipe)
1299 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1300 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1301 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1302 result = runCmd('file %s' % patch_gz)
1303 if 'gzip compressed data' not in result.output:
1304 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1305
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001306 def test_devtool_update_recipe_local_files_subdir(self):
1307 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1308 # SRC_URI such that it overwrites a file that was in an archive that
1309 # was also in SRC_URI
1310 # First, modify the recipe
1311 testrecipe = 'devtool-test-subdir'
1312 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1313 recipefile = bb_vars['FILE']
1314 src_uri = bb_vars['SRC_URI']
1315 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1316 self.track_for_cleanup(tempdir)
1317 self.track_for_cleanup(self.workspacedir)
1318 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1319 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1320 result = runCmd('devtool modify %s' % testrecipe)
1321 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1322 self.assertExists(testfile, 'Extracted source could not be found')
1323 with open(testfile, 'r') as f:
1324 contents = f.read().rstrip()
1325 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1326 # Test devtool update-recipe without modifying any files
1327 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1328 result = runCmd('devtool update-recipe %s' % testrecipe)
1329 expected_status = []
1330 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1331
Andrew Geissler615f2f12022-07-15 14:00:58 -05001332 def test_devtool_finish_modify_git_subdir(self):
1333 # Check preconditions
1334 testrecipe = 'dos2unix'
1335 bb_vars = get_bb_vars(['SRC_URI', 'S', 'WORKDIR', 'FILE'], testrecipe)
1336 self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe)
1337 workdir_git = '%s/git/' % bb_vars['WORKDIR']
1338 if not bb_vars['S'].startswith(workdir_git):
1339 self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe)
1340 subdir = bb_vars['S'].split(workdir_git, 1)[1]
1341 # Clean up anything in the workdir/sysroot/sstate cache
1342 bitbake('%s -c cleansstate' % testrecipe)
1343 # Try modifying a recipe
1344 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1345 self.track_for_cleanup(tempdir)
1346 self.track_for_cleanup(self.workspacedir)
1347 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1348 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1349 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1350 testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c')
1351 self.assertExists(testsrcfile, 'Extracted source could not be found')
1352 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
1353 self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo')
1354 # Check git repo
1355 self._check_src_repo(tempdir)
1356 # Modify file
1357 runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile)
1358 result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir)
1359 # Now try updating original recipe
1360 recipefile = bb_vars['FILE']
1361 recipedir = os.path.dirname(recipefile)
1362 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1363 result = runCmd('devtool update-recipe %s' % testrecipe)
1364 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1365 ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))]
1366 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1367 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
1368 removelines = ['SRC_URI = "git://.*"']
1369 addlines = [
1370 'SRC_URI = "git://.* \\\\',
1371 'file://0001-Add-a-comment.patch;patchdir=.. \\\\',
1372 '"'
1373 ]
1374 self._check_diff(result.output, addlines, removelines)
1375 # Put things back so we can run devtool finish on a different layer
1376 runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1377 # Run devtool finish
1378 res = re.search('recipes-.*', recipedir)
1379 self.assertTrue(res, 'Unable to find recipe subdirectory')
1380 recipesubdir = res[0]
1381 self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir))
1382 result = runCmd('devtool finish %s meta-selftest' % testrecipe)
1383 # Check bbappend file contents
1384 appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe)
1385 with open(appendfn, 'r') as f:
1386 appendlines = f.readlines()
1387 expected_appendlines = [
1388 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
1389 '\n',
1390 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n',
1391 '\n'
1392 ]
1393 self.assertEqual(appendlines, expected_appendlines)
1394 self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch'))
1395 # Try building
1396 bitbake('%s -c patch' % testrecipe)
1397
1398
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001399class DevtoolExtractTests(DevtoolBase):
1400
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001401 def test_devtool_extract(self):
1402 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1403 # Try devtool extract
1404 self.track_for_cleanup(tempdir)
1405 self.track_for_cleanup(self.workspacedir)
1406 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1407 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1408 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1409 self._check_src_repo(tempdir)
1410
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001411 def test_devtool_extract_virtual(self):
1412 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1413 # Try devtool extract
1414 self.track_for_cleanup(tempdir)
1415 self.track_for_cleanup(self.workspacedir)
1416 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1417 result = runCmd('devtool extract virtual/make %s' % tempdir)
1418 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1419 self._check_src_repo(tempdir)
1420
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001421 def test_devtool_reset_all(self):
1422 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1423 self.track_for_cleanup(tempdir)
1424 self.track_for_cleanup(self.workspacedir)
1425 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1426 testrecipe1 = 'mdadm'
1427 testrecipe2 = 'cronie'
1428 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1429 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1430 result = runCmd('devtool build %s' % testrecipe1)
1431 result = runCmd('devtool build %s' % testrecipe2)
1432 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1433 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1434 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1435 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1436 result = runCmd('devtool reset -a')
1437 self.assertIn(testrecipe1, result.output)
1438 self.assertIn(testrecipe2, result.output)
1439 result = runCmd('devtool status')
1440 self.assertNotIn(testrecipe1, result.output)
1441 self.assertNotIn(testrecipe2, result.output)
1442 matches1 = glob.glob(stampprefix1 + '*')
1443 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1444 matches2 = glob.glob(stampprefix2 + '*')
1445 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1446
Patrick Williams45852732022-04-02 08:58:32 -05001447 @OETestTag("runqemu")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001448 def test_devtool_deploy_target(self):
1449 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1450 # unfortunately the runtime tests run under bitbake and you can't run
1451 # devtool within bitbake (since devtool needs to run bitbake itself).
1452 # Additionally we are testing build-time functionality as well, so
1453 # really this has to be done as an oe-selftest test.
1454 #
1455 # Check preconditions
1456 machine = get_bb_var('MACHINE')
1457 if not machine.startswith('qemu'):
1458 self.skipTest('This test only works with qemu machines')
1459 if not os.path.exists('/etc/runqemu-nosudo'):
1460 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1461 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1462 if result.status != 0:
1463 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1464 if result.status != 0:
1465 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1466 for line in result.output.splitlines():
1467 if line.startswith('tap'):
1468 break
1469 else:
1470 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1471 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1472 # Definitions
1473 testrecipe = 'mdadm'
1474 testfile = '/sbin/mdadm'
1475 testimage = 'oe-selftest-image'
1476 testcommand = '/sbin/mdadm --help'
1477 # Build an image to run
1478 bitbake("%s qemu-native qemu-helper-native" % testimage)
1479 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1480 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1481 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1482 # Clean recipe so the first deploy will fail
1483 bitbake("%s -c clean" % testrecipe)
1484 # Try devtool modify
1485 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1486 self.track_for_cleanup(tempdir)
1487 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001488 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001489 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001490 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1491 # Test that deploy-target at this point fails (properly)
1492 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1493 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1494 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1495 result = runCmd('devtool build %s' % testrecipe)
1496 # First try a dry-run of deploy-target
1497 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1498 self.assertIn(' %s' % testfile, result.output)
1499 # Boot the image
1500 with runqemu(testimage) as qemu:
1501 # Now really test deploy-target
1502 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1503 # Run a test command to see if it was installed properly
1504 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1505 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1506 # Check if it deployed all of the files with the right ownership/perms
1507 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1508 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1509 installdir = bb_vars['D']
1510 fakerootenv = bb_vars['FAKEROOTENV']
1511 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001512 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001513 filelist1 = self._process_ls_output(result.output)
1514
1515 # Now look on the target
1516 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1517 self.track_for_cleanup(tempdir2)
1518 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1519 with open(tmpfilelist, 'w') as f:
1520 for line in filelist1:
1521 splitline = line.split()
1522 f.write(splitline[-1] + '\n')
1523 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1524 filelist2 = self._process_ls_output(result.output)
1525 filelist1.sort(key=lambda item: item.split()[-1])
1526 filelist2.sort(key=lambda item: item.split()[-1])
1527 self.assertEqual(filelist1, filelist2)
1528 # Test undeploy-target
1529 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1530 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1531 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1532
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001533 def test_devtool_build_image(self):
1534 """Test devtool build-image plugin"""
1535 # Check preconditions
1536 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1537 image = 'core-image-minimal'
1538 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001539 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001540 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001541 bitbake('%s -c clean' % image)
1542 # Add target and native recipes to workspace
1543 recipes = ['mdadm', 'parted-native']
1544 for recipe in recipes:
1545 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1546 self.track_for_cleanup(tempdir)
1547 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1548 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1549 # Try to build image
1550 result = runCmd('devtool build-image %s' % image)
1551 self.assertNotEqual(result, 0, 'devtool build-image failed')
1552 # Check if image contains expected packages
1553 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1554 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1555 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1556 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1557 for line in f:
1558 splitval = line.split()
1559 if splitval:
1560 pkg = splitval[0]
1561 if pkg in reqpkgs:
1562 reqpkgs.remove(pkg)
1563 if reqpkgs:
1564 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1565
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001566class DevtoolUpgradeTests(DevtoolBase):
1567
Patrick Williams45852732022-04-02 08:58:32 -05001568 def setUp(self):
1569 super().setUp()
1570 try:
1571 runCmd("git config --global user.name")
1572 runCmd("git config --global user.email")
1573 except:
1574 self.skip("Git user.name and user.email must be set")
1575
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001576 def test_devtool_upgrade(self):
1577 # Check preconditions
1578 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1579 self.track_for_cleanup(self.workspacedir)
1580 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1581 # Check parameters
1582 result = runCmd('devtool upgrade -h')
1583 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1584 self.assertIn(param, result.output)
1585 # For the moment, we are using a real recipe.
1586 recipe = 'devtool-upgrade-test1'
1587 version = '1.6.0'
1588 oldrecipefile = get_bb_var('FILE', recipe)
1589 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1590 self.track_for_cleanup(tempdir)
1591 # Check that recipe is not already under devtool control
1592 result = runCmd('devtool status')
1593 self.assertNotIn(recipe, result.output)
1594 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1595 # we are downgrading instead of upgrading.
1596 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1597 # Check if srctree at least is populated
1598 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1599 # Check new recipe subdirectory is present
1600 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1601 # Check new recipe file is present
1602 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1603 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1604 # Check devtool status and make sure recipe is present
1605 result = runCmd('devtool status')
1606 self.assertIn(recipe, result.output)
1607 self.assertIn(tempdir, result.output)
1608 # Check recipe got changed as expected
1609 with open(oldrecipefile + '.upgraded', 'r') as f:
1610 desiredlines = f.readlines()
1611 with open(newrecipefile, 'r') as f:
1612 newlines = f.readlines()
1613 self.assertEqual(desiredlines, newlines)
1614 # Check devtool reset recipe
1615 result = runCmd('devtool reset %s -n' % recipe)
1616 result = runCmd('devtool status')
1617 self.assertNotIn(recipe, result.output)
1618 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1619
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001620 def test_devtool_upgrade_git(self):
1621 # Check preconditions
1622 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1623 self.track_for_cleanup(self.workspacedir)
1624 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1625 recipe = 'devtool-upgrade-test2'
1626 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1627 oldrecipefile = get_bb_var('FILE', recipe)
1628 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1629 self.track_for_cleanup(tempdir)
1630 # Check that recipe is not already under devtool control
1631 result = runCmd('devtool status')
1632 self.assertNotIn(recipe, result.output)
1633 # Check upgrade
1634 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1635 # Check if srctree at least is populated
1636 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1637 # Check new recipe file is present
1638 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1639 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1640 # Check devtool status and make sure recipe is present
1641 result = runCmd('devtool status')
1642 self.assertIn(recipe, result.output)
1643 self.assertIn(tempdir, result.output)
1644 # Check recipe got changed as expected
1645 with open(oldrecipefile + '.upgraded', 'r') as f:
1646 desiredlines = f.readlines()
1647 with open(newrecipefile, 'r') as f:
1648 newlines = f.readlines()
1649 self.assertEqual(desiredlines, newlines)
1650 # Check devtool reset recipe
1651 result = runCmd('devtool reset %s -n' % recipe)
1652 result = runCmd('devtool status')
1653 self.assertNotIn(recipe, result.output)
1654 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1655
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001656 def test_devtool_layer_plugins(self):
1657 """Test that devtool can use plugins from other layers.
1658
1659 This test executes the selftest-reverse command from meta-selftest."""
1660
1661 self.track_for_cleanup(self.workspacedir)
1662 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1663
1664 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1665 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1666 self.assertEqual(result.output, s[::-1])
1667
1668 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1669 dstdir = basedstdir
1670 self.assertExists(dstdir)
1671 for p in paths:
1672 dstdir = os.path.join(dstdir, p)
1673 if not os.path.exists(dstdir):
1674 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001675 if p == "lib":
1676 # Can race with other tests
1677 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1678 else:
1679 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001680 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1681 if srcfile != dstfile:
1682 shutil.copy(srcfile, dstfile)
1683 self.track_for_cleanup(dstfile)
1684
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001685 def test_devtool_load_plugin(self):
1686 """Test that devtool loads only the first found plugin in BBPATH."""
1687
1688 self.track_for_cleanup(self.workspacedir)
1689 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1690
1691 devtool = runCmd("which devtool")
1692 fromname = runCmd("devtool --quiet pluginfile")
1693 srcfile = fromname.output
1694 bbpath = get_bb_var('BBPATH')
1695 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1696 plugincontent = []
1697 with open(srcfile) as fh:
1698 plugincontent = fh.readlines()
1699 try:
1700 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1701 for path in searchpath:
1702 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1703 result = runCmd("devtool --quiet count")
1704 self.assertEqual(result.output, '1')
1705 result = runCmd("devtool --quiet multiloaded")
1706 self.assertEqual(result.output, "no")
1707 for path in searchpath:
1708 result = runCmd("devtool --quiet bbdir")
1709 self.assertEqual(result.output, path)
1710 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1711 finally:
1712 with open(srcfile, 'w') as fh:
1713 fh.writelines(plugincontent)
1714
1715 def _setup_test_devtool_finish_upgrade(self):
1716 # Check preconditions
1717 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1718 self.track_for_cleanup(self.workspacedir)
1719 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1720 # Use a "real" recipe from meta-selftest
1721 recipe = 'devtool-upgrade-test1'
1722 oldversion = '1.5.3'
1723 newversion = '1.6.0'
1724 oldrecipefile = get_bb_var('FILE', recipe)
1725 recipedir = os.path.dirname(oldrecipefile)
1726 result = runCmd('git status --porcelain .', cwd=recipedir)
1727 if result.output.strip():
1728 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1729 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1730 self.track_for_cleanup(tempdir)
1731 # Check that recipe is not already under devtool control
1732 result = runCmd('devtool status')
1733 self.assertNotIn(recipe, result.output)
1734 # Do the upgrade
1735 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1736 # Check devtool status and make sure recipe is present
1737 result = runCmd('devtool status')
1738 self.assertIn(recipe, result.output)
1739 self.assertIn(tempdir, result.output)
1740 # Make a change to the source
1741 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1742 result = runCmd('git status --porcelain', cwd=tempdir)
1743 self.assertIn('M src/pv/number.c', result.output)
1744 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1745 # Check if patch is there
1746 recipedir = os.path.dirname(oldrecipefile)
1747 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1748 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001749 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001750 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001751 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1752 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001753
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001754 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001755 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001756 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1757 self.assertIn('/meta-selftest/', recipedir)
1758 # Try finish to the original layer
1759 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1760 result = runCmd('devtool finish %s meta-selftest' % recipe)
1761 result = runCmd('devtool status')
1762 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1763 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1764 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1765 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001766 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 -05001767 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1768 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1769 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1770 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 -05001771 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 -05001772 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 -05001773 with open(newrecipefile, 'r') as f:
1774 newcontent = f.read()
1775 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1776 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1777 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1778 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1779
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001780
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001781 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001782 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001783 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1784 self.assertIn('/meta-selftest/', recipedir)
1785 # Try finish to a different layer - should create a bbappend
1786 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1787 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1788 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1789 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1790 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1791 self.track_for_cleanup(newrecipedir)
1792 result = runCmd('devtool finish %s oe-core' % recipe)
1793 result = runCmd('devtool status')
1794 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1795 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1796 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1797 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001798 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001799 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1800 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1801 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 -05001802 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 -05001803 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 -05001804 with open(newrecipefile, 'r') as f:
1805 newcontent = f.read()
1806 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1807 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1808 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1809 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 -05001810
1811 def _setup_test_devtool_finish_modify(self):
1812 # Check preconditions
1813 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1814 # Try modifying a recipe
1815 self.track_for_cleanup(self.workspacedir)
1816 recipe = 'mdadm'
1817 oldrecipefile = get_bb_var('FILE', recipe)
1818 recipedir = os.path.dirname(oldrecipefile)
1819 result = runCmd('git status --porcelain .', cwd=recipedir)
1820 if result.output.strip():
1821 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1822 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1823 self.track_for_cleanup(tempdir)
1824 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1825 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1826 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1827 # Test devtool status
1828 result = runCmd('devtool status')
1829 self.assertIn(recipe, result.output)
1830 self.assertIn(tempdir, result.output)
1831 # Make a change to the source
1832 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1833 result = runCmd('git status --porcelain', cwd=tempdir)
1834 self.assertIn('M maps.c', result.output)
1835 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1836 for entry in os.listdir(recipedir):
1837 filesdir = os.path.join(recipedir, entry)
1838 if os.path.isdir(filesdir):
1839 break
1840 else:
1841 self.fail('Unable to find recipe files directory for %s' % recipe)
1842 return recipe, oldrecipefile, recipedir, filesdir
1843
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001844 def test_devtool_finish_modify_origlayer(self):
1845 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1846 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1847 self.assertIn('/meta/', recipedir)
1848 # Try finish to the original layer
1849 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1850 result = runCmd('devtool finish %s meta' % recipe)
1851 result = runCmd('devtool status')
1852 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1853 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1854 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1855 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1856 self._check_repo_status(recipedir, expected_status)
1857
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001858 def test_devtool_finish_modify_otherlayer(self):
1859 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1860 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1861 self.assertIn('/meta/', recipedir)
1862 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
1863 appenddir = os.path.join(get_test_layer(), relpth)
1864 self.track_for_cleanup(appenddir)
1865 # Try finish to the original layer
1866 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1867 result = runCmd('devtool finish %s meta-selftest' % recipe)
1868 result = runCmd('devtool status')
1869 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1870 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1871 result = runCmd('git status --porcelain .', cwd=recipedir)
1872 if result.output.strip():
1873 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
1874 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
1875 recipefn = recipefn.split('_')[0] + '_%'
1876 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
1877 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
1878 newdir = os.path.join(appenddir, recipe)
1879 files = os.listdir(newdir)
1880 foundpatch = None
1881 for fn in files:
1882 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
1883 foundpatch = fn
1884 if not foundpatch:
1885 self.fail('No patch file created next to bbappend')
1886 files.remove(foundpatch)
1887 if files:
1888 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
1889
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001890 def test_devtool_rename(self):
1891 # Check preconditions
1892 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1893 self.track_for_cleanup(self.workspacedir)
1894 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1895
1896 # First run devtool add
1897 # We already have this recipe in OE-Core, but that doesn't matter
1898 recipename = 'i2c-tools'
1899 recipever = '3.1.2'
1900 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
1901 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
1902 def add_recipe():
1903 result = runCmd('devtool add %s' % url)
1904 self.assertExists(recipefile, 'Expected recipe file not created')
1905 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
1906 checkvars = {}
1907 checkvars['S'] = None
1908 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1909 self._test_recipe_contents(recipefile, checkvars, [])
1910 add_recipe()
1911 # Now rename it - change both name and version
1912 newrecipename = 'mynewrecipe'
1913 newrecipever = '456'
1914 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
1915 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
1916 self.assertExists(newrecipefile, 'Recipe file not renamed')
1917 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1918 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
1919 self.assertExists(newsrctree, 'Source directory not renamed')
1920 checkvars = {}
1921 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
1922 checkvars['SRC_URI'] = url
1923 self._test_recipe_contents(newrecipefile, checkvars, [])
1924 # Try again - change just name this time
1925 result = runCmd('devtool reset -n %s' % newrecipename)
1926 shutil.rmtree(newsrctree)
1927 add_recipe()
1928 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
1929 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
1930 self.assertExists(newrecipefile, 'Recipe file not renamed')
1931 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1932 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
1933 checkvars = {}
1934 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
1935 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1936 self._test_recipe_contents(newrecipefile, checkvars, [])
1937 # Try again - change just version this time
1938 result = runCmd('devtool reset -n %s' % newrecipename)
1939 shutil.rmtree(newsrctree)
1940 add_recipe()
1941 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
1942 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
1943 self.assertExists(newrecipefile, 'Recipe file not renamed')
1944 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
1945 checkvars = {}
1946 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
1947 checkvars['SRC_URI'] = url
1948 self._test_recipe_contents(newrecipefile, checkvars, [])
1949
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001950 def test_devtool_virtual_kernel_modify(self):
1951 """
1952 Summary: The purpose of this test case is to verify that
1953 devtool modify works correctly when building
1954 the kernel.
1955 Dependencies: NA
1956 Steps: 1. Build kernel with bitbake.
1957 2. Save the config file generated.
1958 3. Clean the environment.
1959 4. Use `devtool modify virtual/kernel` to validate following:
1960 4.1 The source is checked out correctly.
1961 4.2 The resulting configuration is the same as
1962 what was get on step 2.
1963 4.3 The Kernel can be build correctly.
1964 4.4 Changes made on the source are reflected on the
1965 subsequent builds.
1966 4.5 Changes on the configuration are reflected on the
1967 subsequent builds
1968 Expected: devtool modify is able to checkout the source of the kernel
1969 and modification to the source and configurations are reflected
1970 when building the kernel.
Patrick Williams45852732022-04-02 08:58:32 -05001971 """
1972 kernel_provider = self.td['PREFERRED_PROVIDER_virtual/kernel']
1973
Andrew Geissler82c905d2020-04-13 13:39:40 -05001974 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001975 bitbake('%s -c clean' % kernel_provider)
1976 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1977 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
1978 self.track_for_cleanup(tempdir)
1979 self.track_for_cleanup(tempdir_cfg)
1980 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001981 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04001982 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001983 #Step 1
1984 #Here is just generated the config file instead of all the kernel to optimize the
1985 #time of executing this test case.
1986 bitbake('%s -c configure' % kernel_provider)
1987 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
1988 #Step 2
1989 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
1990 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
1991
1992 tmpconfig = os.path.join(tempdir_cfg, '.config')
1993 #Step 3
1994 bitbake('%s -c clean' % kernel_provider)
1995 #Step 4.1
1996 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
1997 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1998 #Step 4.2
1999 configfile = os.path.join(tempdir,'.config')
Patrick Williams45852732022-04-02 08:58:32 -05002000 runCmd('diff %s %s' % (tmpconfig, configfile))
2001
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002002 #Step 4.3
2003 #NOTE: virtual/kernel is mapped to kernel_provider
Patrick Williams45852732022-04-02 08:58:32 -05002004 runCmd('devtool build %s' % kernel_provider)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002005 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
2006 self.assertExists(kernelfile, 'Kernel was not build correctly')
2007
2008 #Modify the kernel source
Patrick Williams45852732022-04-02 08:58:32 -05002009 modfile = os.path.join(tempdir, 'init/version.c')
2010 runCmd("sed -i 's/Linux/LiNuX/g' %s" % (modfile))
2011
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002012 #Modify the configuration
Patrick Williams45852732022-04-02 08:58:32 -05002013 codeconfigfile = os.path.join(tempdir, '.config.new')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002014 modconfopt = "CONFIG_SG_POOL=n"
Patrick Williams45852732022-04-02 08:58:32 -05002015 runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
2016
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002017 #Build again kernel with devtool
Patrick Williams45852732022-04-02 08:58:32 -05002018 runCmd('devtool build %s' % kernel_provider)
2019
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002020 #Step 4.4
Patrick Williams45852732022-04-02 08:58:32 -05002021 runCmd("grep '%s' %s" % ('LiNuX', kernelfile))
2022
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002023 #Step 4.5
Patrick Williams45852732022-04-02 08:58:32 -05002024 runCmd("grep %s %s" % (modconfopt, codeconfigfile))