blob: 142932e12f50bd68ad8e2e3cfeed29200cd5c512 [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
Patrick Williams92b42cb2022-09-03 06:53:57 -05002# Copyright OpenEmbedded Contributors
3#
Brad Bishopc342db32019-05-15 21:57:59 -04004# SPDX-License-Identifier: MIT
5#
6
Brad Bishopd7bf8c12018-02-25 22:55:05 -05007import os
8import re
9import shutil
10import tempfile
11import glob
12import fnmatch
13
Brad Bishopd7bf8c12018-02-25 22:55:05 -050014from oeqa.selftest.case import OESelftestTestCase
15from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer
16from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer
Patrick Williams45852732022-04-02 08:58:32 -050017from oeqa.core.decorator import OETestTag
Brad Bishopd7bf8c12018-02-25 22:55:05 -050018
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080019oldmetapath = None
20
21def setUpModule():
22 import bb.utils
23
24 global templayerdir
25 templayerdir = tempfile.mkdtemp(prefix='devtoolqa')
26 corecopydir = os.path.join(templayerdir, 'core-copy')
27 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
28 edited_layers = []
29
30 # We need to take a copy of the meta layer so we can modify it and not
31 # have any races against other tests that might be running in parallel
32 # however things like COREBASE mean that you can't just copy meta, you
33 # need the whole repository.
34 def bblayers_edit_cb(layerpath, canonical_layerpath):
35 global oldmetapath
36 if not canonical_layerpath.endswith('/'):
37 # This helps us match exactly when we're using this path later
38 canonical_layerpath += '/'
39 if not edited_layers and canonical_layerpath.endswith('/meta/'):
40 canonical_layerpath = os.path.realpath(canonical_layerpath) + '/'
41 edited_layers.append(layerpath)
42 oldmetapath = os.path.realpath(layerpath)
43 result = runCmd('git rev-parse --show-toplevel', cwd=canonical_layerpath)
44 oldreporoot = result.output.rstrip()
45 newmetapath = os.path.join(corecopydir, os.path.relpath(oldmetapath, oldreporoot))
46 runCmd('git clone %s %s' % (oldreporoot, corecopydir), cwd=templayerdir)
47 # Now we need to copy any modified files
48 # You might ask "why not just copy the entire tree instead of
49 # cloning and doing this?" - well, the problem with that is
50 # TMPDIR or an equally large subdirectory might exist
51 # under COREBASE and we don't want to copy that, so we have
52 # to be selective.
53 result = runCmd('git status --porcelain', cwd=oldreporoot)
54 for line in result.output.splitlines():
55 if line.startswith(' M ') or line.startswith('?? '):
56 relpth = line.split()[1]
57 pth = os.path.join(oldreporoot, relpth)
58 if pth.startswith(canonical_layerpath):
59 if relpth.endswith('/'):
60 destdir = os.path.join(corecopydir, relpth)
Andrew Geisslerc3d88e42020-10-02 09:45:00 -050061 # avoid race condition by not copying .pyc files YPBZ#13421,13803
Andrew Geisslerd1e89492021-02-12 15:35:20 -060062 shutil.copytree(pth, destdir, ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080063 else:
64 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
65 bb.utils.mkdirhier(destdir)
66 shutil.copy2(pth, destdir)
67 return newmetapath
68 else:
69 return layerpath
70 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
71
72def tearDownModule():
73 if oldmetapath:
74 edited_layers = []
75 def bblayers_edit_cb(layerpath, canonical_layerpath):
76 if not edited_layers and canonical_layerpath.endswith('/meta'):
77 edited_layers.append(layerpath)
78 return oldmetapath
79 else:
80 return layerpath
81 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
82 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
83 shutil.rmtree(templayerdir)
84
Andrew Geissler595f6302022-01-24 19:11:47 +000085class DevtoolTestCase(OESelftestTestCase):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080086
87 def setUp(self):
88 """Test case setup function"""
Andrew Geissler595f6302022-01-24 19:11:47 +000089 super(DevtoolTestCase, self).setUp()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080090 self.workspacedir = os.path.join(self.builddir, 'workspace')
91 self.assertTrue(not os.path.exists(self.workspacedir),
92 'This test cannot be run with a workspace directory '
93 'under the build directory')
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080094
95 def _check_src_repo(self, repo_dir):
96 """Check srctree git repository"""
97 self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')),
98 'git repository for external source tree not found')
99 result = runCmd('git status --porcelain', cwd=repo_dir)
100 self.assertEqual(result.output.strip(), "",
101 'Created git repo is not clean')
102 result = runCmd('git symbolic-ref HEAD', cwd=repo_dir)
103 self.assertEqual(result.output.strip(), "refs/heads/devtool",
104 'Wrong branch in git repo')
105
106 def _check_repo_status(self, repo_dir, expected_status):
107 """Check the worktree status of a repository"""
108 result = runCmd('git status . --porcelain',
109 cwd=repo_dir)
110 for line in result.output.splitlines():
111 for ind, (f_status, fn_re) in enumerate(expected_status):
112 if re.match(fn_re, line[3:]):
113 if f_status != line[:2]:
114 self.fail('Unexpected status in line: %s' % line)
115 expected_status.pop(ind)
116 break
117 else:
118 self.fail('Unexpected modified file in line: %s' % line)
119 if expected_status:
120 self.fail('Missing file changes: %s' % expected_status)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500121
122 def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
123 with open(recipefile, 'r') as f:
124 invar = None
125 invalue = None
Brad Bishop6dbb3162019-11-25 09:41:34 -0500126 inherits = set()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500127 for line in f:
128 var = None
129 if invar:
130 value = line.strip().strip('"')
131 if value.endswith('\\'):
132 invalue += ' ' + value[:-1].strip()
133 continue
134 else:
135 invalue += ' ' + value.strip()
136 var = invar
137 value = invalue
138 invar = None
139 elif '=' in line:
140 splitline = line.split('=', 1)
141 var = splitline[0].rstrip()
142 value = splitline[1].strip().strip('"')
143 if value.endswith('\\'):
144 invalue = value[:-1].strip()
145 invar = var
146 continue
147 elif line.startswith('inherit '):
Brad Bishop6dbb3162019-11-25 09:41:34 -0500148 inherits.update(line.split()[1:])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500149
150 if var and var in checkvars:
151 needvalue = checkvars.pop(var)
152 if needvalue is None:
153 self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value))
154 if isinstance(needvalue, set):
155 if var == 'LICENSE':
156 value = set(value.split(' & '))
157 else:
158 value = set(value.split())
159 self.assertEqual(value, needvalue, 'values for %s do not match' % var)
160
161
162 missingvars = {}
163 for var, value in checkvars.items():
164 if value is not None:
165 missingvars[var] = value
166 self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars)
167
168 for inherit in checkinherits:
169 self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
170
171 def _check_bbappend(self, testrecipe, recipefile, appenddir):
172 result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
173 resultlines = result.output.splitlines()
174 inrecipe = False
175 bbappends = []
176 bbappendfile = None
177 for line in resultlines:
178 if inrecipe:
179 if line.startswith(' '):
180 bbappends.append(line.strip())
181 else:
182 break
183 elif line == '%s:' % os.path.basename(recipefile):
184 inrecipe = True
185 self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
186 for bbappend in bbappends:
187 if bbappend.startswith(appenddir):
188 bbappendfile = bbappend
189 break
190 else:
191 self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
192 return bbappendfile
193
194 def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
195 create_temp_layer(templayerdir, templayername, priority, recipepathspec)
196 if addlayer:
197 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
198 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
199
200 def _process_ls_output(self, output):
201 """
202 Convert ls -l output to a format we can reasonably compare from one context
203 to another (e.g. from host to target)
204 """
205 filelist = []
206 for line in output.splitlines():
207 splitline = line.split()
208 if len(splitline) < 8:
209 self.fail('_process_ls_output: invalid output line: %s' % line)
210 # Remove trailing . on perms
211 splitline[0] = splitline[0].rstrip('.')
212 # Remove leading . on paths
213 splitline[-1] = splitline[-1].lstrip('.')
214 # Drop fields we don't want to compare
215 del splitline[7]
216 del splitline[6]
217 del splitline[5]
218 del splitline[4]
219 del splitline[1]
220 filelist.append(' '.join(splitline))
221 return filelist
222
Andrew Geissler615f2f12022-07-15 14:00:58 -0500223 def _check_diff(self, diffoutput, addlines, removelines):
224 """Check output from 'git diff' matches expectation"""
225 remaining_addlines = addlines[:]
226 remaining_removelines = removelines[:]
227 for line in diffoutput.splitlines():
228 if line.startswith('+++') or line.startswith('---'):
229 continue
230 elif line.startswith('+'):
231 matched = False
232 for item in addlines:
233 if re.match(item, line[1:].strip()):
234 matched = True
235 remaining_addlines.remove(item)
236 break
237 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
238 elif line.startswith('-'):
239 matched = False
240 for item in removelines:
241 if re.match(item, line[1:].strip()):
242 matched = True
243 remaining_removelines.remove(item)
244 break
245 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
246 if remaining_addlines:
247 self.fail('Expected added lines not found: %s' % remaining_addlines)
248 if remaining_removelines:
249 self.fail('Expected removed lines not found: %s' % remaining_removelines)
250
Patrick Williams92b42cb2022-09-03 06:53:57 -0500251 def _test_devtool_add_git_url(self, git_url, version, pn, resulting_src_uri):
252 self.track_for_cleanup(self.workspacedir)
253 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
254 result = runCmd('devtool add --version %s %s %s' % (version, pn, git_url))
255 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
256 # Check the recipe name is correct
257 recipefile = get_bb_var('FILE', pn)
258 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
259 self.assertIn(recipefile, result.output)
260 # Test devtool status
261 result = runCmd('devtool status')
262 self.assertIn(pn, result.output)
263 self.assertIn(recipefile, result.output)
264 checkvars = {}
265 checkvars['SRC_URI'] = resulting_src_uri
266 self._test_recipe_contents(recipefile, checkvars, [])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500267
Andrew Geissler595f6302022-01-24 19:11:47 +0000268class DevtoolBase(DevtoolTestCase):
269
270 @classmethod
271 def setUpClass(cls):
272 super(DevtoolBase, cls).setUpClass()
273 bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
274 cls.original_sstate = bb_vars['SSTATE_DIR']
275 cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
276 cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
277 cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
278 % cls.original_sstate)
279
280 @classmethod
281 def tearDownClass(cls):
282 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
283 runCmd('rm -rf %s' % cls.devtool_sstate)
284 super(DevtoolBase, cls).tearDownClass()
285
286 def setUp(self):
287 """Test case setup function"""
288 super(DevtoolBase, self).setUp()
289 self.append_config(self.sstate_conf)
290
291
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500292class DevtoolTests(DevtoolBase):
293
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500294 def test_create_workspace(self):
295 # Check preconditions
296 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400297 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 -0400298 # remove conf/devtool.conf to avoid it corrupting tests
299 devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
300 self.track_for_cleanup(devtoolconf)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500301 # Try creating a workspace layer with a specific path
302 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
303 self.track_for_cleanup(tempdir)
304 result = runCmd('devtool create-workspace %s' % tempdir)
305 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
306 result = runCmd('bitbake-layers show-layers')
307 self.assertIn(tempdir, result.output)
308 # Try creating a workspace layer with the default path
309 self.track_for_cleanup(self.workspacedir)
310 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
311 result = runCmd('devtool create-workspace')
312 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
313 result = runCmd('bitbake-layers show-layers')
314 self.assertNotIn(tempdir, result.output)
315 self.assertIn(self.workspacedir, result.output)
316
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800317class DevtoolAddTests(DevtoolBase):
318
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500319 def test_devtool_add(self):
320 # Fetch source
321 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
322 self.track_for_cleanup(tempdir)
323 pn = 'pv'
324 pv = '1.5.3'
Andrew Geissler09209ee2020-12-13 08:44:15 -0600325 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500326 result = runCmd('wget %s' % url, cwd=tempdir)
327 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
328 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
329 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
330 # Test devtool add
331 self.track_for_cleanup(self.workspacedir)
332 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
333 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
334 result = runCmd('devtool add %s %s' % (pn, srcdir))
335 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
336 # Test devtool status
337 result = runCmd('devtool status')
338 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
339 self.assertIn(recipepath, result.output)
340 self.assertIn(srcdir, result.output)
341 # Test devtool find-recipe
342 result = runCmd('devtool -q find-recipe %s' % pn)
343 self.assertEqual(recipepath, result.output.strip())
344 # Test devtool edit-recipe
345 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
346 self.assertEqual('123 %s' % recipepath, result.output.strip())
347 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
348 bitbake('%s -c cleansstate' % pn)
349 # Test devtool build
350 result = runCmd('devtool build %s' % pn)
351 bb_vars = get_bb_vars(['D', 'bindir'], pn)
352 installdir = bb_vars['D']
353 self.assertTrue(installdir, 'Could not query installdir variable')
354 bindir = bb_vars['bindir']
355 self.assertTrue(bindir, 'Could not query bindir variable')
356 if bindir[0] == '/':
357 bindir = bindir[1:]
358 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
359
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500360 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800361 # We need dbus built so that DEPENDS recognition works
362 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500363 # Fetch source from a remote URL, but do it outside of devtool
364 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
365 self.track_for_cleanup(tempdir)
366 pn = 'dbus-wait'
367 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
368 # We choose an https:// git URL here to check rewriting the URL works
369 url = 'https://git.yoctoproject.org/git/dbus-wait'
370 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
371 # instead of the directory name
372 result = runCmd('git clone %s noname' % url, cwd=tempdir)
373 srcdir = os.path.join(tempdir, 'noname')
374 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
375 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
376 # Test devtool add
377 self.track_for_cleanup(self.workspacedir)
378 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
379 # Don't specify a name since we should be able to auto-detect it
380 result = runCmd('devtool add %s' % srcdir)
381 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
382 # Check the recipe name is correct
383 recipefile = get_bb_var('FILE', pn)
384 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
385 self.assertIn(recipefile, result.output)
386 # Test devtool status
387 result = runCmd('devtool status')
388 self.assertIn(pn, result.output)
389 self.assertIn(srcdir, result.output)
390 self.assertIn(recipefile, result.output)
391 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000392 checkvars['LICENSE'] = 'GPL-2.0-only'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500393 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
394 checkvars['S'] = '${WORKDIR}/git'
395 checkvars['PV'] = '0.1+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000396 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500397 checkvars['SRCREV'] = srcrev
398 checkvars['DEPENDS'] = set(['dbus'])
399 self._test_recipe_contents(recipefile, checkvars, [])
400
Patrick Williams92b42cb2022-09-03 06:53:57 -0500401 def test_devtool_add_git_style1(self):
402 version = 'v3.1.0'
403 pn = 'mbedtls'
404 # this will trigger reformat_git_uri with branch parameter in url
405 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https'"
406 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https"
407 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
408
409 def test_devtool_add_git_style2(self):
410 version = 'v3.1.0'
411 pn = 'mbedtls'
412 # this will trigger reformat_git_uri with branch parameter in url
413 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;protocol=https'"
414 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;protocol=https;branch=master"
415 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
416
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500417 def test_devtool_add_library(self):
418 # Fetch source
419 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
420 self.track_for_cleanup(tempdir)
421 version = '1.1'
422 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
423 result = runCmd('wget %s' % url, cwd=tempdir)
424 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
425 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
426 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
427 # Test devtool add (and use -V so we test that too)
428 self.track_for_cleanup(self.workspacedir)
429 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
430 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
431 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
432 # Test devtool status
433 result = runCmd('devtool status')
434 self.assertIn('libftdi', result.output)
435 self.assertIn(srcdir, result.output)
436 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
437 bitbake('libftdi -c cleansstate')
438 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
439 # There's also the matter of it installing cmake files to a path we don't
440 # normally cover, which triggers the installed-vs-shipped QA test we have
441 # within do_package
442 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
443 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
444 with open(recipefile, 'a') as f:
Patrick Williams213cb262021-08-07 19:21:33 -0500445 f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500446 # We don't have the ability to pick up this dependency automatically yet...
447 f.write('\nDEPENDS += "libusb1"\n')
448 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
449 # Test devtool build
450 result = runCmd('devtool build libftdi')
451 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
452 staging_libdir = bb_vars['TESTLIBOUTPUT']
453 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
454 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)
455 # Test devtool reset
456 stampprefix = bb_vars['STAMP']
457 result = runCmd('devtool reset libftdi')
458 result = runCmd('devtool status')
459 self.assertNotIn('libftdi', result.output)
460 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
461 matches = glob.glob(stampprefix + '*')
462 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
463 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
464
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500465 def test_devtool_add_fetch(self):
466 # Fetch source
467 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
468 self.track_for_cleanup(tempdir)
469 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400470 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500471 testrecipe = 'python-markupsafe'
472 srcdir = os.path.join(tempdir, testrecipe)
473 # Test devtool add
474 self.track_for_cleanup(self.workspacedir)
475 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
476 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
477 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
478 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
479 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
480 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
481 # Test devtool status
482 result = runCmd('devtool status')
483 self.assertIn(testrecipe, result.output)
484 self.assertIn(srcdir, result.output)
485 # Check recipe
486 recipefile = get_bb_var('FILE', testrecipe)
487 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
488 checkvars = {}
489 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
490 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
491 self._test_recipe_contents(recipefile, checkvars, [])
492 # Try with version specified
493 result = runCmd('devtool reset -n %s' % testrecipe)
494 shutil.rmtree(srcdir)
495 fakever = '1.9'
496 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
497 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
498 # Test devtool status
499 result = runCmd('devtool status')
500 self.assertIn(testrecipe, result.output)
501 self.assertIn(srcdir, result.output)
502 # Check recipe
503 recipefile = get_bb_var('FILE', testrecipe)
504 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
505 checkvars = {}
506 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
507 checkvars['SRC_URI'] = url
508 self._test_recipe_contents(recipefile, checkvars, [])
Andrew Geissler615f2f12022-07-15 14:00:58 -0500509
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500510 def test_devtool_add_fetch_git(self):
511 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
512 self.track_for_cleanup(tempdir)
513 url = 'gitsm://git.yoctoproject.org/mraa'
Andrew Geissler595f6302022-01-24 19:11:47 +0000514 url_branch = '%s;branch=master' % url
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500515 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
516 testrecipe = 'mraa'
517 srcdir = os.path.join(tempdir, testrecipe)
518 # Test devtool add
519 self.track_for_cleanup(self.workspacedir)
520 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
521 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
522 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
523 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
524 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
525 # Test devtool status
526 result = runCmd('devtool status')
527 self.assertIn(testrecipe, result.output)
528 self.assertIn(srcdir, result.output)
529 # Check recipe
530 recipefile = get_bb_var('FILE', testrecipe)
531 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
532 checkvars = {}
533 checkvars['S'] = '${WORKDIR}/git'
534 checkvars['PV'] = '1.0+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000535 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500536 checkvars['SRCREV'] = '${AUTOREV}'
537 self._test_recipe_contents(recipefile, checkvars, [])
538 # Try with revision and version specified
539 result = runCmd('devtool reset -n %s' % testrecipe)
540 shutil.rmtree(srcdir)
541 url_rev = '%s;rev=%s' % (url, checkrev)
542 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
543 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
544 # Test devtool status
545 result = runCmd('devtool status')
546 self.assertIn(testrecipe, result.output)
547 self.assertIn(srcdir, result.output)
548 # Check recipe
549 recipefile = get_bb_var('FILE', testrecipe)
550 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
551 checkvars = {}
552 checkvars['S'] = '${WORKDIR}/git'
553 checkvars['PV'] = '1.5+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000554 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500555 checkvars['SRCREV'] = checkrev
556 self._test_recipe_contents(recipefile, checkvars, [])
557
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500558 def test_devtool_add_fetch_simple(self):
559 # Fetch source from a remote URL, auto-detecting name
560 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
561 self.track_for_cleanup(tempdir)
562 testver = '1.6.0'
563 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
564 testrecipe = 'pv'
565 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
566 # Test devtool add
567 self.track_for_cleanup(self.workspacedir)
568 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
569 result = runCmd('devtool add %s' % url)
570 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
571 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
572 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
573 # Test devtool status
574 result = runCmd('devtool status')
575 self.assertIn(testrecipe, result.output)
576 self.assertIn(srcdir, result.output)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500577 # Check recipedevtool add
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500578 recipefile = get_bb_var('FILE', testrecipe)
579 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
580 checkvars = {}
581 checkvars['S'] = None
582 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
583 self._test_recipe_contents(recipefile, checkvars, [])
584
Andrew Geissler82c905d2020-04-13 13:39:40 -0500585 def test_devtool_add_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600586 collections = get_bb_var('BBFILE_COLLECTIONS').split()
587 if "openembedded-layer" not in collections:
588 self.skipTest("Test needs meta-oe for nodejs")
589
Andrew Geissler82c905d2020-04-13 13:39:40 -0500590 pn = 'savoirfairelinux-node-server-example'
591 pv = '1.0.0'
592 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
593 # Test devtool add
594 self.track_for_cleanup(self.workspacedir)
595 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
596 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
597 result = runCmd('devtool add \'%s\'' % url)
598 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
599 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
600 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
601 # Test devtool status
602 result = runCmd('devtool status')
603 self.assertIn(pn, result.output)
604 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
605 bitbake('%s -c cleansstate' % pn)
606 # Test devtool build
607 result = runCmd('devtool build %s' % pn)
608
Andrew Geissler615f2f12022-07-15 14:00:58 -0500609 def test_devtool_add_python_egg_requires(self):
610 # Fetch source
611 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
612 self.track_for_cleanup(tempdir)
613 testver = '0.14.0'
614 url = 'https://files.pythonhosted.org/packages/e9/9e/25d59f5043cf763833b2581c8027fa92342c4cf8ee523b498ecdf460c16d/uvicorn-%s.tar.gz' % testver
615 testrecipe = 'python3-uvicorn'
616 srcdir = os.path.join(tempdir, testrecipe)
617 # Test devtool add
618 self.track_for_cleanup(self.workspacedir)
619 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
620 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
621
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800622class DevtoolModifyTests(DevtoolBase):
623
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500624 def test_devtool_modify(self):
625 import oe.path
626
627 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
628 self.track_for_cleanup(tempdir)
629 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500630 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400631 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500632 result = runCmd('devtool modify mdadm -x %s' % tempdir)
633 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
634 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
635 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
636 self.assertTrue(matches, 'bbappend not created %s' % result.output)
637
638 # Test devtool status
639 result = runCmd('devtool status')
640 self.assertIn('mdadm', result.output)
641 self.assertIn(tempdir, result.output)
642 self._check_src_repo(tempdir)
643
644 bitbake('mdadm -C unpack')
645
646 def check_line(checkfile, expected, message, present=True):
647 # Check for $expected, on a line on its own, in checkfile.
648 with open(checkfile, 'r') as f:
649 if present:
650 self.assertIn(expected + '\n', f, message)
651 else:
652 self.assertNotIn(expected + '\n', f, message)
653
654 modfile = os.path.join(tempdir, 'mdadm.8.in')
655 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
656 pkgd = bb_vars['PKGD']
657 self.assertTrue(pkgd, 'Could not query PKGD variable')
658 mandir = bb_vars['mandir']
659 self.assertTrue(mandir, 'Could not query mandir variable')
660 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
661
662 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
663 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
664
665 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
666 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
667
668 bitbake('mdadm -c package')
669 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
670
671 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
672 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
673
674 bitbake('mdadm -c package')
675 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
676
677 result = runCmd('devtool reset mdadm')
678 result = runCmd('devtool status')
679 self.assertNotIn('mdadm', result.output)
680
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500681 def test_devtool_buildclean(self):
682 def assertFile(path, *paths):
683 f = os.path.join(path, *paths)
684 self.assertExists(f)
685 def assertNoFile(path, *paths):
686 f = os.path.join(path, *paths)
687 self.assertNotExists(f)
688
689 # Clean up anything in the workdir/sysroot/sstate cache
690 bitbake('mdadm m4 -c cleansstate')
691 # Try modifying a recipe
692 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
693 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
694 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
695 self.track_for_cleanup(tempdir_mdadm)
696 self.track_for_cleanup(tempdir_m4)
697 self.track_for_cleanup(builddir_m4)
698 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500699 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400700 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500701 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
702 try:
703 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
704 runCmd('devtool modify m4 -x %s' % tempdir_m4)
705 assertNoFile(tempdir_mdadm, 'mdadm')
706 assertNoFile(builddir_m4, 'src/m4')
707 result = bitbake('m4 -e')
708 result = bitbake('mdadm m4 -c compile')
709 self.assertEqual(result.status, 0)
710 assertFile(tempdir_mdadm, 'mdadm')
711 assertFile(builddir_m4, 'src/m4')
712 # Check that buildclean task exists and does call make clean
713 bitbake('mdadm m4 -c buildclean')
714 assertNoFile(tempdir_mdadm, 'mdadm')
715 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400716 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500717 bitbake('mdadm m4 -c compile')
718 assertFile(tempdir_mdadm, 'mdadm')
719 assertFile(builddir_m4, 'src/m4')
720 bitbake('mdadm m4 -c clean')
721 # Check that buildclean task is run before clean for B == S
722 assertNoFile(tempdir_mdadm, 'mdadm')
723 # Check that buildclean task is not run before clean for B != S
724 assertFile(builddir_m4, 'src/m4')
725 finally:
726 self.delete_recipeinc('m4')
727
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500728 def test_devtool_modify_invalid(self):
729 # Try modifying some recipes
730 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
731 self.track_for_cleanup(tempdir)
732 self.track_for_cleanup(self.workspacedir)
733 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
734
Andrew Geissler5199d832021-09-24 16:47:35 -0500735 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500736 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
737 result = runCmd('bitbake-layers show-recipes gcc-source*')
738 for line in result.output.splitlines():
739 # just match those lines that contain a real target
740 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
741 if m:
742 testrecipes.append(m.group('recipe'))
743 for testrecipe in testrecipes:
744 # Check it's a valid recipe
745 bitbake('%s -e' % testrecipe)
746 # devtool extract should fail
747 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
748 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
749 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
750 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
751 # devtool modify should fail
752 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
753 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
754 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
755
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500756 def test_devtool_modify_native(self):
757 # Check preconditions
758 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
759 # Try modifying some recipes
760 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
761 self.track_for_cleanup(tempdir)
762 self.track_for_cleanup(self.workspacedir)
763 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
764
765 bbclassextended = False
766 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500767 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500768 for testrecipe in testrecipes:
769 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
770 if not bbclassextended:
771 bbclassextended = checkextend
772 if not inheritnative:
773 inheritnative = not checkextend
774 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
775 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
776 result = runCmd('devtool build %s' % testrecipe)
777 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
778 result = runCmd('devtool reset %s' % testrecipe)
779 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
780
781 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
782 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 -0500783
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600784 def test_devtool_modify_localfiles_only(self):
785 # Check preconditions
786 testrecipe = 'base-files'
787 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
788 foundlocalonly = False
789 correct_symlink = False
790 for item in src_uri:
791 if item.startswith('file://'):
792 if '.patch' not in item:
793 foundlocalonly = True
794 else:
795 foundlocalonly = False
796 break
797 self.assertTrue(foundlocalonly, 'This test expects the %s recipe to fetch local files only and it seems that it no longer does' % testrecipe)
798 # Clean up anything in the workdir/sysroot/sstate cache
799 bitbake('%s -c cleansstate' % testrecipe)
800 # Try modifying a recipe
801 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
802 self.track_for_cleanup(tempdir)
803 self.track_for_cleanup(self.workspacedir)
804 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
805 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
806 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
807 srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
808 srclink = os.path.join(tempdir, 'share/dot.bashrc')
809 self.assertExists(srcfile, 'Extracted source could not be found')
810 if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
811 correct_symlink = True
812 self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500813
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600814 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
815 self.assertTrue(matches, 'bbappend not created')
816 # Test devtool status
817 result = runCmd('devtool status')
818 self.assertIn(testrecipe, result.output)
819 self.assertIn(tempdir, result.output)
820 # Try building
821 bitbake(testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500822
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500823 def test_devtool_modify_git(self):
824 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400825 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500826 src_uri = get_bb_var('SRC_URI', testrecipe)
827 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
828 # Clean up anything in the workdir/sysroot/sstate cache
829 bitbake('%s -c cleansstate' % testrecipe)
830 # Try modifying a recipe
831 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
832 self.track_for_cleanup(tempdir)
833 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500834 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400835 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500836 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400837 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500838 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 -0400839 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500840 self.assertTrue(matches, 'bbappend not created')
841 # Test devtool status
842 result = runCmd('devtool status')
843 self.assertIn(testrecipe, result.output)
844 self.assertIn(tempdir, result.output)
845 # Check git repo
846 self._check_src_repo(tempdir)
847 # Try building
848 bitbake(testrecipe)
849
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500850 def test_devtool_modify_localfiles(self):
851 # Check preconditions
852 testrecipe = 'lighttpd'
853 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
854 foundlocal = False
855 for item in src_uri:
856 if item.startswith('file://') and '.patch' not in item:
857 foundlocal = True
858 break
859 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
860 # Clean up anything in the workdir/sysroot/sstate cache
861 bitbake('%s -c cleansstate' % testrecipe)
862 # Try modifying a recipe
863 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
864 self.track_for_cleanup(tempdir)
865 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500866 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400867 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500868 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
869 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
870 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
871 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
872 self.assertTrue(matches, 'bbappend not created')
873 # Test devtool status
874 result = runCmd('devtool status')
875 self.assertIn(testrecipe, result.output)
876 self.assertIn(tempdir, result.output)
877 # Try building
878 bitbake(testrecipe)
879
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500880 def test_devtool_modify_virtual(self):
881 # Try modifying a virtual recipe
882 virtrecipe = 'virtual/make'
883 realrecipe = 'make'
884 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
885 self.track_for_cleanup(tempdir)
886 self.track_for_cleanup(self.workspacedir)
887 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
888 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
889 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
890 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
891 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
892 self.assertTrue(matches, 'bbappend not created %s' % result.output)
893 # Test devtool status
894 result = runCmd('devtool status')
895 self.assertNotIn(virtrecipe, result.output)
896 self.assertIn(realrecipe, result.output)
897 # Check git repo
898 self._check_src_repo(tempdir)
899 # This is probably sufficient
900
Andrew Geisslerf0343792020-11-18 10:42:21 -0600901 def test_devtool_modify_overrides(self):
902 # Try modifying a recipe with patches in overrides
903 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
904 self.track_for_cleanup(tempdir)
905 self.track_for_cleanup(self.workspacedir)
906 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
907 result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
908
909 self._check_src_repo(tempdir)
910 source = os.path.join(tempdir, "source")
911 def check(branch, expected):
912 runCmd('git -C %s checkout %s' % (tempdir, branch))
913 with open(source, "rt") as f:
914 content = f.read()
915 self.assertEquals(content, expected)
916 check('devtool', 'This is a test for something\n')
917 check('devtool-no-overrides', 'This is a test for something\n')
918 check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
919 check('devtool-override-qemux86', 'This is a test for qemux86\n')
920
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800921class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500922
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500923 def test_devtool_update_recipe(self):
924 # Check preconditions
925 testrecipe = 'minicom'
926 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
927 recipefile = bb_vars['FILE']
928 src_uri = bb_vars['SRC_URI']
929 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
930 self._check_repo_status(os.path.dirname(recipefile), [])
931 # First, modify a recipe
932 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
933 self.track_for_cleanup(tempdir)
934 self.track_for_cleanup(self.workspacedir)
935 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
936 # (don't bother with cleaning the recipe on teardown, we won't be building it)
937 # We don't use -x here so that we test the behaviour of devtool modify without it
938 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
939 # Check git repo
940 self._check_src_repo(tempdir)
941 # Add a couple of commits
942 # FIXME: this only tests adding, need to also test update and remove
943 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
944 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
945 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
946 result = runCmd('git add devtool-new-file', cwd=tempdir)
947 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
948 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
949 result = runCmd('devtool update-recipe %s' % testrecipe)
950 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
951 ('??', '.*/0001-Change-the-README.patch$'),
952 ('??', '.*/0002-Add-a-new-file.patch$')]
953 self._check_repo_status(os.path.dirname(recipefile), expected_status)
954
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500955 def test_devtool_update_recipe_git(self):
956 # Check preconditions
957 testrecipe = 'mtd-utils'
958 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
959 recipefile = bb_vars['FILE']
960 src_uri = bb_vars['SRC_URI']
961 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
962 patches = []
963 for entry in src_uri.split():
964 if entry.startswith('file://') and entry.endswith('.patch'):
965 patches.append(entry[7:].split(';')[0])
966 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
967 self._check_repo_status(os.path.dirname(recipefile), [])
968 # First, modify a recipe
969 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
970 self.track_for_cleanup(tempdir)
971 self.track_for_cleanup(self.workspacedir)
972 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
973 # (don't bother with cleaning the recipe on teardown, we won't be building it)
974 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
975 # Check git repo
976 self._check_src_repo(tempdir)
977 # Add a couple of commits
978 # FIXME: this only tests adding, need to also test update and remove
979 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
980 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
981 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
982 result = runCmd('git add devtool-new-file', cwd=tempdir)
983 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
984 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
985 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
986 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
987 [(' D', '.*/%s$' % patch) for patch in patches]
988 self._check_repo_status(os.path.dirname(recipefile), expected_status)
989
990 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +0000991 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"']
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500992 srcurilines = src_uri.split()
993 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
994 srcurilines.append('"')
995 removelines = ['SRCREV = ".*"'] + srcurilines
Andrew Geissler615f2f12022-07-15 14:00:58 -0500996 self._check_diff(result.output, addlines, removelines)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500997 # Now try with auto mode
998 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
999 result = runCmd('devtool update-recipe %s' % testrecipe)
1000 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
1001 topleveldir = result.output.strip()
1002 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
1003 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
1004 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
1005 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
1006 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1007
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001008 def test_devtool_update_recipe_append(self):
1009 # Check preconditions
1010 testrecipe = 'mdadm'
1011 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1012 recipefile = bb_vars['FILE']
1013 src_uri = bb_vars['SRC_URI']
1014 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1015 self._check_repo_status(os.path.dirname(recipefile), [])
1016 # First, modify a recipe
1017 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1018 tempsrcdir = os.path.join(tempdir, 'source')
1019 templayerdir = os.path.join(tempdir, 'layer')
1020 self.track_for_cleanup(tempdir)
1021 self.track_for_cleanup(self.workspacedir)
1022 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1023 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1024 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1025 # Check git repo
1026 self._check_src_repo(tempsrcdir)
1027 # Add a commit
1028 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
1029 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1030 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1031 # Create a temporary layer and add it to bblayers.conf
1032 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
1033 # Create the bbappend
1034 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1035 self.assertNotIn('WARNING:', result.output)
1036 # Check recipe is still clean
1037 self._check_repo_status(os.path.dirname(recipefile), [])
1038 # Check bbappend was created
1039 splitpath = os.path.dirname(recipefile).split(os.sep)
1040 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1041 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1042 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
1043 self.assertExists(patchfile, 'Patch file not created')
1044
1045 # Check bbappend contents
Patrick Williams213cb262021-08-07 19:21:33 -05001046 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001047 '\n',
1048 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
1049 '\n']
1050 with open(bbappendfile, 'r') as f:
1051 self.assertEqual(expectedlines, f.readlines())
1052
1053 # Check we can run it again and bbappend isn't modified
1054 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1055 with open(bbappendfile, 'r') as f:
1056 self.assertEqual(expectedlines, f.readlines())
1057 # Drop new commit and check patch gets deleted
1058 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1059 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1060 self.assertNotExists(patchfile, 'Patch file not deleted')
Patrick Williams213cb262021-08-07 19:21:33 -05001061 expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001062 '\n']
1063 with open(bbappendfile, 'r') as f:
1064 self.assertEqual(expectedlines2, f.readlines())
1065 # Put commit back and check we can run it if layer isn't in bblayers.conf
1066 os.remove(bbappendfile)
1067 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1068 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1069 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1070 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1071 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
1072 with open(bbappendfile, 'r') as f:
1073 self.assertEqual(expectedlines, f.readlines())
1074 # Deleting isn't expected to work under these circumstances
1075
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001076 def test_devtool_update_recipe_append_git(self):
1077 # Check preconditions
1078 testrecipe = 'mtd-utils'
1079 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1080 recipefile = bb_vars['FILE']
1081 src_uri = bb_vars['SRC_URI']
1082 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1083 for entry in src_uri.split():
1084 if entry.startswith('git://'):
1085 git_uri = entry
1086 break
1087 self._check_repo_status(os.path.dirname(recipefile), [])
1088 # First, modify a recipe
1089 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1090 tempsrcdir = os.path.join(tempdir, 'source')
1091 templayerdir = os.path.join(tempdir, 'layer')
1092 self.track_for_cleanup(tempdir)
1093 self.track_for_cleanup(self.workspacedir)
1094 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1095 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1096 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1097 # Check git repo
1098 self._check_src_repo(tempsrcdir)
1099 # Add a commit
1100 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
1101 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1102 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1103 # Create a temporary layer
1104 os.makedirs(os.path.join(templayerdir, 'conf'))
1105 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
1106 f.write('BBPATH .= ":${LAYERDIR}"\n')
1107 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
1108 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
1109 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
1110 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
1111 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Brad Bishop316dfdd2018-06-25 12:45:53 -04001112 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "${LAYERSERIES_COMPAT_core}"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001113 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
1114 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
1115 # Create the bbappend
1116 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1117 self.assertNotIn('WARNING:', result.output)
1118 # Check recipe is still clean
1119 self._check_repo_status(os.path.dirname(recipefile), [])
1120 # Check bbappend was created
1121 splitpath = os.path.dirname(recipefile).split(os.sep)
1122 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1123 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1124 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1125
1126 # Check bbappend contents
1127 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1128 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1129 '\n',
1130 'SRC_URI = "%s"\n' % git_uri,
1131 '\n'])
1132 with open(bbappendfile, 'r') as f:
1133 self.assertEqual(expectedlines, set(f.readlines()))
1134
1135 # Check we can run it again and bbappend isn't modified
1136 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1137 with open(bbappendfile, 'r') as f:
1138 self.assertEqual(expectedlines, set(f.readlines()))
1139 # Drop new commit and check SRCREV changes
1140 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1141 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1142 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1143 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1144 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1145 '\n',
1146 'SRC_URI = "%s"\n' % git_uri,
1147 '\n'])
1148 with open(bbappendfile, 'r') as f:
1149 self.assertEqual(expectedlines, set(f.readlines()))
1150 # Put commit back and check we can run it if layer isn't in bblayers.conf
1151 os.remove(bbappendfile)
1152 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1153 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1154 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1155 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1156 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1157 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1158 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1159 '\n',
1160 'SRC_URI = "%s"\n' % git_uri,
1161 '\n'])
1162 with open(bbappendfile, 'r') as f:
1163 self.assertEqual(expectedlines, set(f.readlines()))
1164 # Deleting isn't expected to work under these circumstances
1165
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001166 def test_devtool_update_recipe_local_files(self):
1167 """Check that local source files are copied over instead of patched"""
1168 testrecipe = 'makedevs'
1169 recipefile = get_bb_var('FILE', testrecipe)
1170 # Setup srctree for modifying the recipe
1171 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1172 self.track_for_cleanup(tempdir)
1173 self.track_for_cleanup(self.workspacedir)
1174 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1175 # (don't bother with cleaning the recipe on teardown, we won't be
1176 # building it)
1177 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1178 # Check git repo
1179 self._check_src_repo(tempdir)
1180 # Try building just to ensure we haven't broken that
1181 bitbake("%s" % testrecipe)
1182 # Edit / commit local source
1183 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1184 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1185 runCmd('echo "Bar" > new-file', cwd=tempdir)
1186 runCmd('git add new-file', cwd=tempdir)
1187 runCmd('git commit -m "Add new file"', cwd=tempdir)
1188 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1189 os.path.dirname(recipefile))
1190 runCmd('devtool update-recipe %s' % testrecipe)
1191 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1192 (' M', '.*/makedevs/makedevs.c$'),
1193 ('??', '.*/makedevs/new-local$'),
1194 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1195 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1196
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001197 def test_devtool_update_recipe_local_files_2(self):
1198 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001199 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001200 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001201 recipedir = os.path.dirname(recipefile)
1202 result = runCmd('git status --porcelain .', cwd=recipedir)
1203 if result.output.strip():
1204 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001205 # Setup srctree for modifying the recipe
1206 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1207 self.track_for_cleanup(tempdir)
1208 self.track_for_cleanup(self.workspacedir)
1209 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1210 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1211 # Check git repo
1212 self._check_src_repo(tempdir)
1213 # Add oe-local-files to Git
1214 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1215 runCmd('git add oe-local-files', cwd=tempdir)
1216 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1217 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001218 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001219 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001220 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001221 runCmd('git commit -m"Remove file"', cwd=tempdir)
1222 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1223 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1224 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1225 runCmd('echo "Gar" > new-file', cwd=tempdir)
1226 runCmd('git add new-file', cwd=tempdir)
1227 runCmd('git commit -m "Add new file"', cwd=tempdir)
1228 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1229 os.path.dirname(recipefile))
1230 # Checkout unmodified file to working copy -> devtool should still pick
1231 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001232 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001233 runCmd('devtool update-recipe %s' % testrecipe)
1234 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001235 (' M', '.*/file1$'),
1236 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001237 ('??', '.*/new-local$'),
1238 ('??', '.*/0001-Add-new-file.patch$')]
1239 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1240
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001241 def test_devtool_update_recipe_with_gitignore(self):
1242 # First, modify the recipe
1243 testrecipe = 'devtool-test-ignored'
1244 bb_vars = get_bb_vars(['FILE'], testrecipe)
1245 recipefile = bb_vars['FILE']
1246 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1247 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
1248 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1249 self.track_for_cleanup(tempdir)
1250 self.track_for_cleanup(self.workspacedir)
1251 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1252 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1253 result = runCmd('devtool modify %s' % testrecipe)
1254 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1255 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1256 # Check recipe got changed as expected
1257 with open(newpatchfile, 'r') as f:
1258 desiredlines = f.readlines()
1259 with open(patchfile, 'r') as f:
1260 newlines = f.readlines()
1261 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1262 # which changes the metadata subject which is added into the patch, but keep
1263 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1264 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1265 self.assertEqual(desiredlines[5:], newlines[5:])
1266
1267 def test_devtool_update_recipe_long_filename(self):
1268 # First, modify the recipe
1269 testrecipe = 'devtool-test-long-filename'
1270 bb_vars = get_bb_vars(['FILE'], testrecipe)
1271 recipefile = bb_vars['FILE']
1272 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1273 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1274 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1275 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1276 self.track_for_cleanup(tempdir)
1277 self.track_for_cleanup(self.workspacedir)
1278 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1279 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1280 result = runCmd('devtool modify %s' % testrecipe)
1281 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1282 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1283 # Check recipe got changed as expected
1284 with open(newpatchfile, 'r') as f:
1285 desiredlines = f.readlines()
1286 with open(patchfile, 'r') as f:
1287 newlines = f.readlines()
1288 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1289 # which changes the metadata subject which is added into the patch, but keep
1290 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1291 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1292 self.assertEqual(desiredlines[5:], newlines[5:])
1293
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001294 def test_devtool_update_recipe_local_files_3(self):
1295 # First, modify the recipe
1296 testrecipe = 'devtool-test-localonly'
1297 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1298 recipefile = bb_vars['FILE']
1299 src_uri = bb_vars['SRC_URI']
1300 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1301 self.track_for_cleanup(tempdir)
1302 self.track_for_cleanup(self.workspacedir)
1303 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1304 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1305 result = runCmd('devtool modify %s' % testrecipe)
1306 # Modify one file
1307 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1308 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1309 result = runCmd('devtool update-recipe %s' % testrecipe)
1310 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1311 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1312
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001313 def test_devtool_update_recipe_local_patch_gz(self):
1314 # First, modify the recipe
1315 testrecipe = 'devtool-test-patch-gz'
1316 if get_bb_var('DISTRO') == 'poky-tiny':
1317 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1318 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1319 recipefile = bb_vars['FILE']
1320 src_uri = bb_vars['SRC_URI']
1321 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1322 self.track_for_cleanup(tempdir)
1323 self.track_for_cleanup(self.workspacedir)
1324 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1325 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1326 result = runCmd('devtool modify %s' % testrecipe)
1327 # Modify one file
1328 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1329 runCmd('echo "Another line" >> README', cwd=srctree)
1330 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1331 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1332 result = runCmd('devtool update-recipe %s' % testrecipe)
1333 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1334 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1335 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1336 result = runCmd('file %s' % patch_gz)
1337 if 'gzip compressed data' not in result.output:
1338 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1339
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001340 def test_devtool_update_recipe_local_files_subdir(self):
1341 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1342 # SRC_URI such that it overwrites a file that was in an archive that
1343 # was also in SRC_URI
1344 # First, modify the recipe
1345 testrecipe = 'devtool-test-subdir'
1346 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1347 recipefile = bb_vars['FILE']
1348 src_uri = bb_vars['SRC_URI']
1349 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1350 self.track_for_cleanup(tempdir)
1351 self.track_for_cleanup(self.workspacedir)
1352 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1353 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1354 result = runCmd('devtool modify %s' % testrecipe)
1355 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1356 self.assertExists(testfile, 'Extracted source could not be found')
1357 with open(testfile, 'r') as f:
1358 contents = f.read().rstrip()
1359 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1360 # Test devtool update-recipe without modifying any files
1361 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1362 result = runCmd('devtool update-recipe %s' % testrecipe)
1363 expected_status = []
1364 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1365
Andrew Geissler615f2f12022-07-15 14:00:58 -05001366 def test_devtool_finish_modify_git_subdir(self):
1367 # Check preconditions
1368 testrecipe = 'dos2unix'
1369 bb_vars = get_bb_vars(['SRC_URI', 'S', 'WORKDIR', 'FILE'], testrecipe)
1370 self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe)
1371 workdir_git = '%s/git/' % bb_vars['WORKDIR']
1372 if not bb_vars['S'].startswith(workdir_git):
1373 self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe)
1374 subdir = bb_vars['S'].split(workdir_git, 1)[1]
1375 # Clean up anything in the workdir/sysroot/sstate cache
1376 bitbake('%s -c cleansstate' % testrecipe)
1377 # Try modifying a recipe
1378 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1379 self.track_for_cleanup(tempdir)
1380 self.track_for_cleanup(self.workspacedir)
1381 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1382 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1383 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1384 testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c')
1385 self.assertExists(testsrcfile, 'Extracted source could not be found')
1386 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
1387 self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo')
1388 # Check git repo
1389 self._check_src_repo(tempdir)
1390 # Modify file
1391 runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile)
1392 result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir)
1393 # Now try updating original recipe
1394 recipefile = bb_vars['FILE']
1395 recipedir = os.path.dirname(recipefile)
1396 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1397 result = runCmd('devtool update-recipe %s' % testrecipe)
1398 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1399 ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))]
1400 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1401 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
1402 removelines = ['SRC_URI = "git://.*"']
1403 addlines = [
1404 'SRC_URI = "git://.* \\\\',
1405 'file://0001-Add-a-comment.patch;patchdir=.. \\\\',
1406 '"'
1407 ]
1408 self._check_diff(result.output, addlines, removelines)
1409 # Put things back so we can run devtool finish on a different layer
1410 runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1411 # Run devtool finish
1412 res = re.search('recipes-.*', recipedir)
1413 self.assertTrue(res, 'Unable to find recipe subdirectory')
1414 recipesubdir = res[0]
1415 self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir))
1416 result = runCmd('devtool finish %s meta-selftest' % testrecipe)
1417 # Check bbappend file contents
1418 appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe)
1419 with open(appendfn, 'r') as f:
1420 appendlines = f.readlines()
1421 expected_appendlines = [
1422 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
1423 '\n',
1424 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n',
1425 '\n'
1426 ]
1427 self.assertEqual(appendlines, expected_appendlines)
1428 self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch'))
1429 # Try building
1430 bitbake('%s -c patch' % testrecipe)
1431
1432
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001433class DevtoolExtractTests(DevtoolBase):
1434
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001435 def test_devtool_extract(self):
1436 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1437 # Try devtool extract
1438 self.track_for_cleanup(tempdir)
1439 self.track_for_cleanup(self.workspacedir)
1440 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1441 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1442 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1443 self._check_src_repo(tempdir)
1444
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001445 def test_devtool_extract_virtual(self):
1446 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1447 # Try devtool extract
1448 self.track_for_cleanup(tempdir)
1449 self.track_for_cleanup(self.workspacedir)
1450 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1451 result = runCmd('devtool extract virtual/make %s' % tempdir)
1452 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1453 self._check_src_repo(tempdir)
1454
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001455 def test_devtool_reset_all(self):
1456 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1457 self.track_for_cleanup(tempdir)
1458 self.track_for_cleanup(self.workspacedir)
1459 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1460 testrecipe1 = 'mdadm'
1461 testrecipe2 = 'cronie'
1462 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1463 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1464 result = runCmd('devtool build %s' % testrecipe1)
1465 result = runCmd('devtool build %s' % testrecipe2)
1466 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1467 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1468 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1469 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1470 result = runCmd('devtool reset -a')
1471 self.assertIn(testrecipe1, result.output)
1472 self.assertIn(testrecipe2, result.output)
1473 result = runCmd('devtool status')
1474 self.assertNotIn(testrecipe1, result.output)
1475 self.assertNotIn(testrecipe2, result.output)
1476 matches1 = glob.glob(stampprefix1 + '*')
1477 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1478 matches2 = glob.glob(stampprefix2 + '*')
1479 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1480
Patrick Williams45852732022-04-02 08:58:32 -05001481 @OETestTag("runqemu")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001482 def test_devtool_deploy_target(self):
1483 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1484 # unfortunately the runtime tests run under bitbake and you can't run
1485 # devtool within bitbake (since devtool needs to run bitbake itself).
1486 # Additionally we are testing build-time functionality as well, so
1487 # really this has to be done as an oe-selftest test.
1488 #
1489 # Check preconditions
1490 machine = get_bb_var('MACHINE')
1491 if not machine.startswith('qemu'):
1492 self.skipTest('This test only works with qemu machines')
1493 if not os.path.exists('/etc/runqemu-nosudo'):
1494 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1495 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1496 if result.status != 0:
1497 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1498 if result.status != 0:
1499 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1500 for line in result.output.splitlines():
1501 if line.startswith('tap'):
1502 break
1503 else:
1504 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1505 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1506 # Definitions
1507 testrecipe = 'mdadm'
1508 testfile = '/sbin/mdadm'
1509 testimage = 'oe-selftest-image'
1510 testcommand = '/sbin/mdadm --help'
1511 # Build an image to run
1512 bitbake("%s qemu-native qemu-helper-native" % testimage)
1513 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1514 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1515 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1516 # Clean recipe so the first deploy will fail
1517 bitbake("%s -c clean" % testrecipe)
1518 # Try devtool modify
1519 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1520 self.track_for_cleanup(tempdir)
1521 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001522 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001523 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001524 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1525 # Test that deploy-target at this point fails (properly)
1526 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1527 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1528 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1529 result = runCmd('devtool build %s' % testrecipe)
1530 # First try a dry-run of deploy-target
1531 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1532 self.assertIn(' %s' % testfile, result.output)
1533 # Boot the image
1534 with runqemu(testimage) as qemu:
1535 # Now really test deploy-target
1536 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1537 # Run a test command to see if it was installed properly
1538 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1539 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1540 # Check if it deployed all of the files with the right ownership/perms
1541 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1542 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1543 installdir = bb_vars['D']
1544 fakerootenv = bb_vars['FAKEROOTENV']
1545 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001546 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001547 filelist1 = self._process_ls_output(result.output)
1548
1549 # Now look on the target
1550 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1551 self.track_for_cleanup(tempdir2)
1552 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1553 with open(tmpfilelist, 'w') as f:
1554 for line in filelist1:
1555 splitline = line.split()
1556 f.write(splitline[-1] + '\n')
1557 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1558 filelist2 = self._process_ls_output(result.output)
1559 filelist1.sort(key=lambda item: item.split()[-1])
1560 filelist2.sort(key=lambda item: item.split()[-1])
1561 self.assertEqual(filelist1, filelist2)
1562 # Test undeploy-target
1563 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1564 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1565 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1566
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001567 def test_devtool_build_image(self):
1568 """Test devtool build-image plugin"""
1569 # Check preconditions
1570 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1571 image = 'core-image-minimal'
1572 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001573 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001574 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001575 bitbake('%s -c clean' % image)
1576 # Add target and native recipes to workspace
1577 recipes = ['mdadm', 'parted-native']
1578 for recipe in recipes:
1579 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1580 self.track_for_cleanup(tempdir)
1581 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1582 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1583 # Try to build image
1584 result = runCmd('devtool build-image %s' % image)
1585 self.assertNotEqual(result, 0, 'devtool build-image failed')
1586 # Check if image contains expected packages
1587 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1588 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1589 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1590 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1591 for line in f:
1592 splitval = line.split()
1593 if splitval:
1594 pkg = splitval[0]
1595 if pkg in reqpkgs:
1596 reqpkgs.remove(pkg)
1597 if reqpkgs:
1598 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1599
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001600class DevtoolUpgradeTests(DevtoolBase):
1601
Patrick Williams45852732022-04-02 08:58:32 -05001602 def setUp(self):
1603 super().setUp()
1604 try:
1605 runCmd("git config --global user.name")
1606 runCmd("git config --global user.email")
1607 except:
1608 self.skip("Git user.name and user.email must be set")
1609
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001610 def test_devtool_upgrade(self):
1611 # Check preconditions
1612 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1613 self.track_for_cleanup(self.workspacedir)
1614 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1615 # Check parameters
1616 result = runCmd('devtool upgrade -h')
1617 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1618 self.assertIn(param, result.output)
1619 # For the moment, we are using a real recipe.
1620 recipe = 'devtool-upgrade-test1'
1621 version = '1.6.0'
1622 oldrecipefile = get_bb_var('FILE', recipe)
1623 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1624 self.track_for_cleanup(tempdir)
1625 # Check that recipe is not already under devtool control
1626 result = runCmd('devtool status')
1627 self.assertNotIn(recipe, result.output)
1628 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1629 # we are downgrading instead of upgrading.
1630 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1631 # Check if srctree at least is populated
1632 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1633 # Check new recipe subdirectory is present
1634 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1635 # Check new recipe file is present
1636 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1637 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1638 # Check devtool status and make sure recipe is present
1639 result = runCmd('devtool status')
1640 self.assertIn(recipe, result.output)
1641 self.assertIn(tempdir, result.output)
1642 # Check recipe got changed as expected
1643 with open(oldrecipefile + '.upgraded', 'r') as f:
1644 desiredlines = f.readlines()
1645 with open(newrecipefile, 'r') as f:
1646 newlines = f.readlines()
1647 self.assertEqual(desiredlines, newlines)
1648 # Check devtool reset recipe
1649 result = runCmd('devtool reset %s -n' % recipe)
1650 result = runCmd('devtool status')
1651 self.assertNotIn(recipe, result.output)
1652 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1653
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001654 def test_devtool_upgrade_git(self):
1655 # Check preconditions
1656 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1657 self.track_for_cleanup(self.workspacedir)
1658 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1659 recipe = 'devtool-upgrade-test2'
1660 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1661 oldrecipefile = get_bb_var('FILE', recipe)
1662 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1663 self.track_for_cleanup(tempdir)
1664 # Check that recipe is not already under devtool control
1665 result = runCmd('devtool status')
1666 self.assertNotIn(recipe, result.output)
1667 # Check upgrade
1668 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1669 # Check if srctree at least is populated
1670 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1671 # Check new recipe file is present
1672 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1673 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1674 # Check devtool status and make sure recipe is present
1675 result = runCmd('devtool status')
1676 self.assertIn(recipe, result.output)
1677 self.assertIn(tempdir, result.output)
1678 # Check recipe got changed as expected
1679 with open(oldrecipefile + '.upgraded', 'r') as f:
1680 desiredlines = f.readlines()
1681 with open(newrecipefile, 'r') as f:
1682 newlines = f.readlines()
1683 self.assertEqual(desiredlines, newlines)
1684 # Check devtool reset recipe
1685 result = runCmd('devtool reset %s -n' % recipe)
1686 result = runCmd('devtool status')
1687 self.assertNotIn(recipe, result.output)
1688 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1689
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001690 def test_devtool_layer_plugins(self):
1691 """Test that devtool can use plugins from other layers.
1692
1693 This test executes the selftest-reverse command from meta-selftest."""
1694
1695 self.track_for_cleanup(self.workspacedir)
1696 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1697
1698 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1699 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1700 self.assertEqual(result.output, s[::-1])
1701
1702 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1703 dstdir = basedstdir
1704 self.assertExists(dstdir)
1705 for p in paths:
1706 dstdir = os.path.join(dstdir, p)
1707 if not os.path.exists(dstdir):
1708 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001709 if p == "lib":
1710 # Can race with other tests
1711 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1712 else:
1713 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001714 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1715 if srcfile != dstfile:
1716 shutil.copy(srcfile, dstfile)
1717 self.track_for_cleanup(dstfile)
1718
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001719 def test_devtool_load_plugin(self):
1720 """Test that devtool loads only the first found plugin in BBPATH."""
1721
1722 self.track_for_cleanup(self.workspacedir)
1723 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1724
1725 devtool = runCmd("which devtool")
1726 fromname = runCmd("devtool --quiet pluginfile")
1727 srcfile = fromname.output
1728 bbpath = get_bb_var('BBPATH')
1729 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1730 plugincontent = []
1731 with open(srcfile) as fh:
1732 plugincontent = fh.readlines()
1733 try:
1734 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1735 for path in searchpath:
1736 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1737 result = runCmd("devtool --quiet count")
1738 self.assertEqual(result.output, '1')
1739 result = runCmd("devtool --quiet multiloaded")
1740 self.assertEqual(result.output, "no")
1741 for path in searchpath:
1742 result = runCmd("devtool --quiet bbdir")
1743 self.assertEqual(result.output, path)
1744 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1745 finally:
1746 with open(srcfile, 'w') as fh:
1747 fh.writelines(plugincontent)
1748
1749 def _setup_test_devtool_finish_upgrade(self):
1750 # Check preconditions
1751 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1752 self.track_for_cleanup(self.workspacedir)
1753 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1754 # Use a "real" recipe from meta-selftest
1755 recipe = 'devtool-upgrade-test1'
1756 oldversion = '1.5.3'
1757 newversion = '1.6.0'
1758 oldrecipefile = get_bb_var('FILE', recipe)
1759 recipedir = os.path.dirname(oldrecipefile)
1760 result = runCmd('git status --porcelain .', cwd=recipedir)
1761 if result.output.strip():
1762 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1763 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1764 self.track_for_cleanup(tempdir)
1765 # Check that recipe is not already under devtool control
1766 result = runCmd('devtool status')
1767 self.assertNotIn(recipe, result.output)
1768 # Do the upgrade
1769 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1770 # Check devtool status and make sure recipe is present
1771 result = runCmd('devtool status')
1772 self.assertIn(recipe, result.output)
1773 self.assertIn(tempdir, result.output)
1774 # Make a change to the source
1775 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1776 result = runCmd('git status --porcelain', cwd=tempdir)
1777 self.assertIn('M src/pv/number.c', result.output)
1778 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1779 # Check if patch is there
1780 recipedir = os.path.dirname(oldrecipefile)
1781 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1782 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001783 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001784 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001785 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1786 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001787
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001788 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001789 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001790 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1791 self.assertIn('/meta-selftest/', recipedir)
1792 # Try finish to the original layer
1793 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1794 result = runCmd('devtool finish %s meta-selftest' % recipe)
1795 result = runCmd('devtool status')
1796 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1797 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1798 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1799 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001800 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 -05001801 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1802 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1803 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1804 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 -05001805 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 -05001806 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 -05001807 with open(newrecipefile, 'r') as f:
1808 newcontent = f.read()
1809 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1810 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1811 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1812 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1813
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001814
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001815 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001816 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001817 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1818 self.assertIn('/meta-selftest/', recipedir)
1819 # Try finish to a different layer - should create a bbappend
1820 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1821 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1822 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1823 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1824 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1825 self.track_for_cleanup(newrecipedir)
1826 result = runCmd('devtool finish %s oe-core' % recipe)
1827 result = runCmd('devtool status')
1828 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1829 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1830 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1831 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001832 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001833 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1834 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1835 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 -05001836 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 -05001837 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 -05001838 with open(newrecipefile, 'r') as f:
1839 newcontent = f.read()
1840 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1841 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1842 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1843 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 -05001844
1845 def _setup_test_devtool_finish_modify(self):
1846 # Check preconditions
1847 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1848 # Try modifying a recipe
1849 self.track_for_cleanup(self.workspacedir)
1850 recipe = 'mdadm'
1851 oldrecipefile = get_bb_var('FILE', recipe)
1852 recipedir = os.path.dirname(oldrecipefile)
1853 result = runCmd('git status --porcelain .', cwd=recipedir)
1854 if result.output.strip():
1855 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1856 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1857 self.track_for_cleanup(tempdir)
1858 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1859 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1860 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1861 # Test devtool status
1862 result = runCmd('devtool status')
1863 self.assertIn(recipe, result.output)
1864 self.assertIn(tempdir, result.output)
1865 # Make a change to the source
1866 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1867 result = runCmd('git status --porcelain', cwd=tempdir)
1868 self.assertIn('M maps.c', result.output)
1869 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1870 for entry in os.listdir(recipedir):
1871 filesdir = os.path.join(recipedir, entry)
1872 if os.path.isdir(filesdir):
1873 break
1874 else:
1875 self.fail('Unable to find recipe files directory for %s' % recipe)
1876 return recipe, oldrecipefile, recipedir, filesdir
1877
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001878 def test_devtool_finish_modify_origlayer(self):
1879 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1880 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1881 self.assertIn('/meta/', recipedir)
1882 # Try finish to the original layer
1883 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1884 result = runCmd('devtool finish %s meta' % recipe)
1885 result = runCmd('devtool status')
1886 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1887 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1888 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1889 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1890 self._check_repo_status(recipedir, expected_status)
1891
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001892 def test_devtool_finish_modify_otherlayer(self):
1893 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1894 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1895 self.assertIn('/meta/', recipedir)
1896 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
1897 appenddir = os.path.join(get_test_layer(), relpth)
1898 self.track_for_cleanup(appenddir)
1899 # Try finish to the original layer
1900 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1901 result = runCmd('devtool finish %s meta-selftest' % recipe)
1902 result = runCmd('devtool status')
1903 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1904 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1905 result = runCmd('git status --porcelain .', cwd=recipedir)
1906 if result.output.strip():
1907 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
1908 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
1909 recipefn = recipefn.split('_')[0] + '_%'
1910 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
1911 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
1912 newdir = os.path.join(appenddir, recipe)
1913 files = os.listdir(newdir)
1914 foundpatch = None
1915 for fn in files:
1916 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
1917 foundpatch = fn
1918 if not foundpatch:
1919 self.fail('No patch file created next to bbappend')
1920 files.remove(foundpatch)
1921 if files:
1922 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
1923
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001924 def test_devtool_rename(self):
1925 # Check preconditions
1926 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1927 self.track_for_cleanup(self.workspacedir)
1928 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1929
1930 # First run devtool add
1931 # We already have this recipe in OE-Core, but that doesn't matter
1932 recipename = 'i2c-tools'
1933 recipever = '3.1.2'
1934 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
1935 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
1936 def add_recipe():
1937 result = runCmd('devtool add %s' % url)
1938 self.assertExists(recipefile, 'Expected recipe file not created')
1939 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
1940 checkvars = {}
1941 checkvars['S'] = None
1942 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1943 self._test_recipe_contents(recipefile, checkvars, [])
1944 add_recipe()
1945 # Now rename it - change both name and version
1946 newrecipename = 'mynewrecipe'
1947 newrecipever = '456'
1948 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
1949 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
1950 self.assertExists(newrecipefile, 'Recipe file not renamed')
1951 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1952 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
1953 self.assertExists(newsrctree, 'Source directory not renamed')
1954 checkvars = {}
1955 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
1956 checkvars['SRC_URI'] = url
1957 self._test_recipe_contents(newrecipefile, checkvars, [])
1958 # Try again - change just name this time
1959 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001960 add_recipe()
1961 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
1962 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
1963 self.assertExists(newrecipefile, 'Recipe file not renamed')
1964 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1965 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
1966 checkvars = {}
1967 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
1968 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1969 self._test_recipe_contents(newrecipefile, checkvars, [])
1970 # Try again - change just version this time
1971 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001972 add_recipe()
1973 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
1974 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
1975 self.assertExists(newrecipefile, 'Recipe file not renamed')
1976 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
1977 checkvars = {}
1978 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
1979 checkvars['SRC_URI'] = url
1980 self._test_recipe_contents(newrecipefile, checkvars, [])
1981
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001982 def test_devtool_virtual_kernel_modify(self):
1983 """
1984 Summary: The purpose of this test case is to verify that
1985 devtool modify works correctly when building
1986 the kernel.
1987 Dependencies: NA
1988 Steps: 1. Build kernel with bitbake.
1989 2. Save the config file generated.
1990 3. Clean the environment.
1991 4. Use `devtool modify virtual/kernel` to validate following:
1992 4.1 The source is checked out correctly.
1993 4.2 The resulting configuration is the same as
1994 what was get on step 2.
1995 4.3 The Kernel can be build correctly.
1996 4.4 Changes made on the source are reflected on the
1997 subsequent builds.
1998 4.5 Changes on the configuration are reflected on the
1999 subsequent builds
2000 Expected: devtool modify is able to checkout the source of the kernel
2001 and modification to the source and configurations are reflected
2002 when building the kernel.
Patrick Williams45852732022-04-02 08:58:32 -05002003 """
2004 kernel_provider = self.td['PREFERRED_PROVIDER_virtual/kernel']
2005
Andrew Geissler82c905d2020-04-13 13:39:40 -05002006 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002007 bitbake('%s -c clean' % kernel_provider)
2008 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2009 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
2010 self.track_for_cleanup(tempdir)
2011 self.track_for_cleanup(tempdir_cfg)
2012 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002013 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04002014 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002015 #Step 1
2016 #Here is just generated the config file instead of all the kernel to optimize the
2017 #time of executing this test case.
2018 bitbake('%s -c configure' % kernel_provider)
2019 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
2020 #Step 2
2021 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
2022 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
2023
2024 tmpconfig = os.path.join(tempdir_cfg, '.config')
2025 #Step 3
2026 bitbake('%s -c clean' % kernel_provider)
2027 #Step 4.1
2028 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
2029 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2030 #Step 4.2
2031 configfile = os.path.join(tempdir,'.config')
Patrick Williams45852732022-04-02 08:58:32 -05002032 runCmd('diff %s %s' % (tmpconfig, configfile))
2033
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002034 #Step 4.3
2035 #NOTE: virtual/kernel is mapped to kernel_provider
Patrick Williams45852732022-04-02 08:58:32 -05002036 runCmd('devtool build %s' % kernel_provider)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002037 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
2038 self.assertExists(kernelfile, 'Kernel was not build correctly')
2039
2040 #Modify the kernel source
Patrick Williams45852732022-04-02 08:58:32 -05002041 modfile = os.path.join(tempdir, 'init/version.c')
2042 runCmd("sed -i 's/Linux/LiNuX/g' %s" % (modfile))
2043
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002044 #Modify the configuration
Patrick Williams45852732022-04-02 08:58:32 -05002045 codeconfigfile = os.path.join(tempdir, '.config.new')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002046 modconfopt = "CONFIG_SG_POOL=n"
Patrick Williams45852732022-04-02 08:58:32 -05002047 runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
2048
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002049 #Build again kernel with devtool
Patrick Williams45852732022-04-02 08:58:32 -05002050 runCmd('devtool build %s' % kernel_provider)
2051
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002052 #Step 4.4
Patrick Williams45852732022-04-02 08:58:32 -05002053 runCmd("grep '%s' %s" % ('LiNuX', kernelfile))
2054
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002055 #Step 4.5
Patrick Williams45852732022-04-02 08:58:32 -05002056 runCmd("grep %s %s" % (modconfopt, codeconfigfile))