blob: 15249b70fdda91fa34705928e19291cd6ece9e7d [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
Patrick Williams169d7bc2024-01-05 11:33:25 -06007import errno
Brad Bishopd7bf8c12018-02-25 22:55:05 -05008import os
9import re
10import shutil
11import tempfile
12import glob
13import fnmatch
Patrick Williamse760df82023-05-26 11:10:49 -050014import unittest
Brad Bishopd7bf8c12018-02-25 22:55:05 -050015
Brad Bishopd7bf8c12018-02-25 22:55:05 -050016from oeqa.selftest.case import OESelftestTestCase
17from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer
18from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer
Patrick Williams45852732022-04-02 08:58:32 -050019from oeqa.core.decorator import OETestTag
Brad Bishopd7bf8c12018-02-25 22:55:05 -050020
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080021oldmetapath = None
22
23def setUpModule():
24 import bb.utils
25
26 global templayerdir
27 templayerdir = tempfile.mkdtemp(prefix='devtoolqa')
28 corecopydir = os.path.join(templayerdir, 'core-copy')
29 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
30 edited_layers = []
Patrick Williamsac13d5f2023-11-24 18:59:46 -060031 # make sure user doesn't have a local workspace
32 result = runCmd('bitbake-layers show-layers')
33 assert "workspacelayer" not in result.output, "Devtool test suite cannot be run with a local workspace directory"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080034
35 # We need to take a copy of the meta layer so we can modify it and not
36 # have any races against other tests that might be running in parallel
37 # however things like COREBASE mean that you can't just copy meta, you
38 # need the whole repository.
39 def bblayers_edit_cb(layerpath, canonical_layerpath):
40 global oldmetapath
41 if not canonical_layerpath.endswith('/'):
42 # This helps us match exactly when we're using this path later
43 canonical_layerpath += '/'
44 if not edited_layers and canonical_layerpath.endswith('/meta/'):
45 canonical_layerpath = os.path.realpath(canonical_layerpath) + '/'
46 edited_layers.append(layerpath)
47 oldmetapath = os.path.realpath(layerpath)
Patrick Williamse760df82023-05-26 11:10:49 -050048
49 # when downloading poky from tar.gz some tests will be skipped (BUG 12389)
50 try:
51 runCmd('git rev-parse --is-inside-work-tree', cwd=canonical_layerpath)
52 except:
53 raise unittest.SkipTest("devtool tests require folder to be a git repo")
54
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080055 result = runCmd('git rev-parse --show-toplevel', cwd=canonical_layerpath)
56 oldreporoot = result.output.rstrip()
57 newmetapath = os.path.join(corecopydir, os.path.relpath(oldmetapath, oldreporoot))
Patrick Williams169d7bc2024-01-05 11:33:25 -060058 runCmd('git clone file://%s %s' % (oldreporoot, corecopydir), cwd=templayerdir)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080059 # Now we need to copy any modified files
60 # You might ask "why not just copy the entire tree instead of
61 # cloning and doing this?" - well, the problem with that is
62 # TMPDIR or an equally large subdirectory might exist
63 # under COREBASE and we don't want to copy that, so we have
64 # to be selective.
65 result = runCmd('git status --porcelain', cwd=oldreporoot)
66 for line in result.output.splitlines():
67 if line.startswith(' M ') or line.startswith('?? '):
68 relpth = line.split()[1]
69 pth = os.path.join(oldreporoot, relpth)
70 if pth.startswith(canonical_layerpath):
71 if relpth.endswith('/'):
72 destdir = os.path.join(corecopydir, relpth)
Andrew Geisslerc3d88e42020-10-02 09:45:00 -050073 # avoid race condition by not copying .pyc files YPBZ#13421,13803
Andrew Geisslerd1e89492021-02-12 15:35:20 -060074 shutil.copytree(pth, destdir, ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080075 else:
76 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
77 bb.utils.mkdirhier(destdir)
78 shutil.copy2(pth, destdir)
79 return newmetapath
80 else:
81 return layerpath
82 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
83
84def tearDownModule():
85 if oldmetapath:
86 edited_layers = []
87 def bblayers_edit_cb(layerpath, canonical_layerpath):
88 if not edited_layers and canonical_layerpath.endswith('/meta'):
89 edited_layers.append(layerpath)
90 return oldmetapath
91 else:
92 return layerpath
93 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
94 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
95 shutil.rmtree(templayerdir)
96
Andrew Geissler595f6302022-01-24 19:11:47 +000097class DevtoolTestCase(OESelftestTestCase):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080098
99 def setUp(self):
100 """Test case setup function"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000101 super(DevtoolTestCase, self).setUp()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800102 self.workspacedir = os.path.join(self.builddir, 'workspace')
103 self.assertTrue(not os.path.exists(self.workspacedir),
104 'This test cannot be run with a workspace directory '
105 'under the build directory')
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800106
107 def _check_src_repo(self, repo_dir):
108 """Check srctree git repository"""
109 self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')),
110 'git repository for external source tree not found')
111 result = runCmd('git status --porcelain', cwd=repo_dir)
112 self.assertEqual(result.output.strip(), "",
113 'Created git repo is not clean')
114 result = runCmd('git symbolic-ref HEAD', cwd=repo_dir)
115 self.assertEqual(result.output.strip(), "refs/heads/devtool",
116 'Wrong branch in git repo')
117
118 def _check_repo_status(self, repo_dir, expected_status):
119 """Check the worktree status of a repository"""
120 result = runCmd('git status . --porcelain',
121 cwd=repo_dir)
122 for line in result.output.splitlines():
123 for ind, (f_status, fn_re) in enumerate(expected_status):
124 if re.match(fn_re, line[3:]):
125 if f_status != line[:2]:
126 self.fail('Unexpected status in line: %s' % line)
127 expected_status.pop(ind)
128 break
129 else:
130 self.fail('Unexpected modified file in line: %s' % line)
131 if expected_status:
132 self.fail('Missing file changes: %s' % expected_status)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500133
134 def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
135 with open(recipefile, 'r') as f:
136 invar = None
137 invalue = None
Brad Bishop6dbb3162019-11-25 09:41:34 -0500138 inherits = set()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500139 for line in f:
140 var = None
141 if invar:
142 value = line.strip().strip('"')
143 if value.endswith('\\'):
144 invalue += ' ' + value[:-1].strip()
145 continue
146 else:
147 invalue += ' ' + value.strip()
148 var = invar
149 value = invalue
150 invar = None
151 elif '=' in line:
152 splitline = line.split('=', 1)
153 var = splitline[0].rstrip()
154 value = splitline[1].strip().strip('"')
155 if value.endswith('\\'):
156 invalue = value[:-1].strip()
157 invar = var
158 continue
159 elif line.startswith('inherit '):
Brad Bishop6dbb3162019-11-25 09:41:34 -0500160 inherits.update(line.split()[1:])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500161
162 if var and var in checkvars:
163 needvalue = checkvars.pop(var)
164 if needvalue is None:
165 self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value))
166 if isinstance(needvalue, set):
167 if var == 'LICENSE':
168 value = set(value.split(' & '))
169 else:
170 value = set(value.split())
171 self.assertEqual(value, needvalue, 'values for %s do not match' % var)
172
173
174 missingvars = {}
175 for var, value in checkvars.items():
176 if value is not None:
177 missingvars[var] = value
178 self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars)
179
180 for inherit in checkinherits:
181 self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
182
183 def _check_bbappend(self, testrecipe, recipefile, appenddir):
184 result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
185 resultlines = result.output.splitlines()
186 inrecipe = False
187 bbappends = []
188 bbappendfile = None
189 for line in resultlines:
190 if inrecipe:
191 if line.startswith(' '):
192 bbappends.append(line.strip())
193 else:
194 break
195 elif line == '%s:' % os.path.basename(recipefile):
196 inrecipe = True
197 self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
198 for bbappend in bbappends:
199 if bbappend.startswith(appenddir):
200 bbappendfile = bbappend
201 break
202 else:
203 self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
204 return bbappendfile
205
206 def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
207 create_temp_layer(templayerdir, templayername, priority, recipepathspec)
208 if addlayer:
209 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
210 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
211
212 def _process_ls_output(self, output):
213 """
214 Convert ls -l output to a format we can reasonably compare from one context
215 to another (e.g. from host to target)
216 """
217 filelist = []
218 for line in output.splitlines():
219 splitline = line.split()
220 if len(splitline) < 8:
221 self.fail('_process_ls_output: invalid output line: %s' % line)
222 # Remove trailing . on perms
223 splitline[0] = splitline[0].rstrip('.')
224 # Remove leading . on paths
225 splitline[-1] = splitline[-1].lstrip('.')
226 # Drop fields we don't want to compare
227 del splitline[7]
228 del splitline[6]
229 del splitline[5]
230 del splitline[4]
231 del splitline[1]
232 filelist.append(' '.join(splitline))
233 return filelist
234
Andrew Geissler615f2f12022-07-15 14:00:58 -0500235 def _check_diff(self, diffoutput, addlines, removelines):
236 """Check output from 'git diff' matches expectation"""
237 remaining_addlines = addlines[:]
238 remaining_removelines = removelines[:]
239 for line in diffoutput.splitlines():
240 if line.startswith('+++') or line.startswith('---'):
241 continue
242 elif line.startswith('+'):
243 matched = False
244 for item in addlines:
245 if re.match(item, line[1:].strip()):
246 matched = True
247 remaining_addlines.remove(item)
248 break
249 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
250 elif line.startswith('-'):
251 matched = False
252 for item in removelines:
253 if re.match(item, line[1:].strip()):
254 matched = True
255 remaining_removelines.remove(item)
256 break
257 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
258 if remaining_addlines:
259 self.fail('Expected added lines not found: %s' % remaining_addlines)
260 if remaining_removelines:
261 self.fail('Expected removed lines not found: %s' % remaining_removelines)
262
Andrew Geissler220dafd2023-10-04 10:18:08 -0500263 def _check_runqemu_prerequisites(self):
264 """Check runqemu is available
265
266 Whilst some tests would seemingly be better placed as a runtime test,
267 unfortunately the runtime tests run under bitbake and you can't run
268 devtool within bitbake (since devtool needs to run bitbake itself).
269 Additionally we are testing build-time functionality as well, so
270 really this has to be done as an oe-selftest test.
271 """
272 machine = get_bb_var('MACHINE')
273 if not machine.startswith('qemu'):
274 self.skipTest('This test only works with qemu machines')
275 if not os.path.exists('/etc/runqemu-nosudo'):
276 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
277 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
278 if result.status != 0:
279 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
280 if result.status != 0:
281 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
282 for line in result.output.splitlines():
283 if line.startswith('tap'):
284 break
285 else:
286 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
287
Patrick Williams92b42cb2022-09-03 06:53:57 -0500288 def _test_devtool_add_git_url(self, git_url, version, pn, resulting_src_uri):
289 self.track_for_cleanup(self.workspacedir)
290 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
291 result = runCmd('devtool add --version %s %s %s' % (version, pn, git_url))
292 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
293 # Check the recipe name is correct
294 recipefile = get_bb_var('FILE', pn)
295 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
296 self.assertIn(recipefile, result.output)
297 # Test devtool status
298 result = runCmd('devtool status')
299 self.assertIn(pn, result.output)
300 self.assertIn(recipefile, result.output)
301 checkvars = {}
302 checkvars['SRC_URI'] = resulting_src_uri
303 self._test_recipe_contents(recipefile, checkvars, [])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500304
Andrew Geissler595f6302022-01-24 19:11:47 +0000305class DevtoolBase(DevtoolTestCase):
306
307 @classmethod
308 def setUpClass(cls):
309 super(DevtoolBase, cls).setUpClass()
310 bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
311 cls.original_sstate = bb_vars['SSTATE_DIR']
312 cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
313 cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
314 cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
315 % cls.original_sstate)
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500316 cls.sstate_conf += ('BB_HASHSERVE_UPSTREAM = "hashserv.yocto.io:8687"\n')
Andrew Geissler595f6302022-01-24 19:11:47 +0000317
318 @classmethod
319 def tearDownClass(cls):
320 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
321 runCmd('rm -rf %s' % cls.devtool_sstate)
322 super(DevtoolBase, cls).tearDownClass()
323
324 def setUp(self):
325 """Test case setup function"""
326 super(DevtoolBase, self).setUp()
327 self.append_config(self.sstate_conf)
328
329
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500330class DevtoolTests(DevtoolBase):
331
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500332 def test_create_workspace(self):
333 # Check preconditions
334 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400335 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 -0400336 # remove conf/devtool.conf to avoid it corrupting tests
337 devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
338 self.track_for_cleanup(devtoolconf)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500339 # Try creating a workspace layer with a specific path
340 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
341 self.track_for_cleanup(tempdir)
342 result = runCmd('devtool create-workspace %s' % tempdir)
343 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
344 result = runCmd('bitbake-layers show-layers')
345 self.assertIn(tempdir, result.output)
346 # Try creating a workspace layer with the default path
347 self.track_for_cleanup(self.workspacedir)
348 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
349 result = runCmd('devtool create-workspace')
350 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
351 result = runCmd('bitbake-layers show-layers')
352 self.assertNotIn(tempdir, result.output)
353 self.assertIn(self.workspacedir, result.output)
354
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800355class DevtoolAddTests(DevtoolBase):
356
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500357 def test_devtool_add(self):
358 # Fetch source
359 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
360 self.track_for_cleanup(tempdir)
361 pn = 'pv'
362 pv = '1.5.3'
Andrew Geissler09209ee2020-12-13 08:44:15 -0600363 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500364 result = runCmd('wget %s' % url, cwd=tempdir)
365 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
366 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
367 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
368 # Test devtool add
369 self.track_for_cleanup(self.workspacedir)
370 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
371 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
372 result = runCmd('devtool add %s %s' % (pn, srcdir))
373 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
374 # Test devtool status
375 result = runCmd('devtool status')
376 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
377 self.assertIn(recipepath, result.output)
378 self.assertIn(srcdir, result.output)
379 # Test devtool find-recipe
380 result = runCmd('devtool -q find-recipe %s' % pn)
381 self.assertEqual(recipepath, result.output.strip())
382 # Test devtool edit-recipe
383 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
384 self.assertEqual('123 %s' % recipepath, result.output.strip())
385 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
386 bitbake('%s -c cleansstate' % pn)
387 # Test devtool build
388 result = runCmd('devtool build %s' % pn)
389 bb_vars = get_bb_vars(['D', 'bindir'], pn)
390 installdir = bb_vars['D']
391 self.assertTrue(installdir, 'Could not query installdir variable')
392 bindir = bb_vars['bindir']
393 self.assertTrue(bindir, 'Could not query bindir variable')
394 if bindir[0] == '/':
395 bindir = bindir[1:]
396 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
397
Andrew Geissler8f840682023-07-21 09:09:43 -0500398 def test_devtool_add_binary(self):
399 # Create a binary package containing a known test file
400 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
401 self.track_for_cleanup(tempdir)
402 pn = 'tst-bin'
403 pv = '1.0'
404 test_file_dir = "var/lib/%s/" % pn
405 test_file_name = "test_file"
406 test_file_content = "TEST CONTENT"
407 test_file_package_root = os.path.join(tempdir, pn)
408 test_file_dir_full = os.path.join(test_file_package_root, test_file_dir)
409 bb.utils.mkdirhier(test_file_dir_full)
410 with open(os.path.join(test_file_dir_full, test_file_name), "w") as f:
411 f.write(test_file_content)
412 bin_package_path = os.path.join(tempdir, "%s.tar.gz" % pn)
413 runCmd("tar czf %s -C %s ." % (bin_package_path, test_file_package_root))
414
415 # Test devtool add -b on the binary package
416 self.track_for_cleanup(self.workspacedir)
417 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
418 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
419 result = runCmd('devtool add -b %s %s' % (pn, bin_package_path))
420 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
421
422 # Build the resulting recipe
423 result = runCmd('devtool build %s' % pn)
424 installdir = get_bb_var('D', pn)
425 self.assertTrue(installdir, 'Could not query installdir variable')
426
427 # Check that a known file from the binary package has indeed been installed
428 self.assertTrue(os.path.isfile(os.path.join(installdir, test_file_dir, test_file_name)), '%s not found in D' % test_file_name)
429
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500430 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800431 # We need dbus built so that DEPENDS recognition works
432 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500433 # Fetch source from a remote URL, but do it outside of devtool
434 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
435 self.track_for_cleanup(tempdir)
436 pn = 'dbus-wait'
437 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
438 # We choose an https:// git URL here to check rewriting the URL works
439 url = 'https://git.yoctoproject.org/git/dbus-wait'
440 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
441 # instead of the directory name
442 result = runCmd('git clone %s noname' % url, cwd=tempdir)
443 srcdir = os.path.join(tempdir, 'noname')
444 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
445 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
446 # Test devtool add
447 self.track_for_cleanup(self.workspacedir)
448 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
449 # Don't specify a name since we should be able to auto-detect it
450 result = runCmd('devtool add %s' % srcdir)
451 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
452 # Check the recipe name is correct
453 recipefile = get_bb_var('FILE', pn)
454 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
455 self.assertIn(recipefile, result.output)
456 # Test devtool status
457 result = runCmd('devtool status')
458 self.assertIn(pn, result.output)
459 self.assertIn(srcdir, result.output)
460 self.assertIn(recipefile, result.output)
461 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000462 checkvars['LICENSE'] = 'GPL-2.0-only'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500463 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
464 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400465 checkvars['PV'] = '0.1+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000466 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500467 checkvars['SRCREV'] = srcrev
468 checkvars['DEPENDS'] = set(['dbus'])
469 self._test_recipe_contents(recipefile, checkvars, [])
470
Patrick Williams92b42cb2022-09-03 06:53:57 -0500471 def test_devtool_add_git_style1(self):
472 version = 'v3.1.0'
473 pn = 'mbedtls'
474 # this will trigger reformat_git_uri with branch parameter in url
475 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https'"
476 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https"
477 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
478
479 def test_devtool_add_git_style2(self):
480 version = 'v3.1.0'
481 pn = 'mbedtls'
482 # this will trigger reformat_git_uri with branch parameter in url
483 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;protocol=https'"
484 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;protocol=https;branch=master"
485 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
486
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500487 def test_devtool_add_library(self):
488 # Fetch source
489 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
490 self.track_for_cleanup(tempdir)
491 version = '1.1'
492 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
493 result = runCmd('wget %s' % url, cwd=tempdir)
494 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
495 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
496 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
497 # Test devtool add (and use -V so we test that too)
498 self.track_for_cleanup(self.workspacedir)
499 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
500 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
501 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
502 # Test devtool status
503 result = runCmd('devtool status')
504 self.assertIn('libftdi', result.output)
505 self.assertIn(srcdir, result.output)
506 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
507 bitbake('libftdi -c cleansstate')
508 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
509 # There's also the matter of it installing cmake files to a path we don't
510 # normally cover, which triggers the installed-vs-shipped QA test we have
511 # within do_package
512 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
513 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
514 with open(recipefile, 'a') as f:
Patrick Williams213cb262021-08-07 19:21:33 -0500515 f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500516 # We don't have the ability to pick up this dependency automatically yet...
517 f.write('\nDEPENDS += "libusb1"\n')
518 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
519 # Test devtool build
520 result = runCmd('devtool build libftdi')
521 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
522 staging_libdir = bb_vars['TESTLIBOUTPUT']
523 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
524 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)
525 # Test devtool reset
526 stampprefix = bb_vars['STAMP']
527 result = runCmd('devtool reset libftdi')
528 result = runCmd('devtool status')
529 self.assertNotIn('libftdi', result.output)
530 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
531 matches = glob.glob(stampprefix + '*')
532 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
533 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
534
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500535 def test_devtool_add_fetch(self):
536 # Fetch source
537 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
538 self.track_for_cleanup(tempdir)
539 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400540 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500541 testrecipe = 'python-markupsafe'
542 srcdir = os.path.join(tempdir, testrecipe)
543 # Test devtool add
544 self.track_for_cleanup(self.workspacedir)
545 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
546 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Patrick Williams169d7bc2024-01-05 11:33:25 -0600547 result = runCmd('devtool add --no-pypi %s %s -f %s' % (testrecipe, srcdir, url))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500548 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
549 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
550 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
551 # Test devtool status
552 result = runCmd('devtool status')
553 self.assertIn(testrecipe, result.output)
554 self.assertIn(srcdir, result.output)
555 # Check recipe
556 recipefile = get_bb_var('FILE', testrecipe)
557 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
558 checkvars = {}
559 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
560 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
561 self._test_recipe_contents(recipefile, checkvars, [])
562 # Try with version specified
563 result = runCmd('devtool reset -n %s' % testrecipe)
564 shutil.rmtree(srcdir)
565 fakever = '1.9'
Patrick Williams169d7bc2024-01-05 11:33:25 -0600566 result = runCmd('devtool add --no-pypi %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500567 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
568 # Test devtool status
569 result = runCmd('devtool status')
570 self.assertIn(testrecipe, result.output)
571 self.assertIn(srcdir, result.output)
572 # Check recipe
573 recipefile = get_bb_var('FILE', testrecipe)
574 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
575 checkvars = {}
576 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
577 checkvars['SRC_URI'] = url
578 self._test_recipe_contents(recipefile, checkvars, [])
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600579
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500580 def test_devtool_add_fetch_git(self):
581 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
582 self.track_for_cleanup(tempdir)
583 url = 'gitsm://git.yoctoproject.org/mraa'
Andrew Geissler595f6302022-01-24 19:11:47 +0000584 url_branch = '%s;branch=master' % url
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500585 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
586 testrecipe = 'mraa'
587 srcdir = os.path.join(tempdir, testrecipe)
588 # Test devtool add
589 self.track_for_cleanup(self.workspacedir)
590 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
591 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
592 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
593 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
594 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
595 # Test devtool status
596 result = runCmd('devtool status')
597 self.assertIn(testrecipe, result.output)
598 self.assertIn(srcdir, result.output)
599 # Check recipe
600 recipefile = get_bb_var('FILE', testrecipe)
601 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
602 checkvars = {}
603 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400604 checkvars['PV'] = '1.0+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000605 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500606 checkvars['SRCREV'] = '${AUTOREV}'
607 self._test_recipe_contents(recipefile, checkvars, [])
608 # Try with revision and version specified
609 result = runCmd('devtool reset -n %s' % testrecipe)
610 shutil.rmtree(srcdir)
611 url_rev = '%s;rev=%s' % (url, checkrev)
612 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
613 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
614 # Test devtool status
615 result = runCmd('devtool status')
616 self.assertIn(testrecipe, result.output)
617 self.assertIn(srcdir, result.output)
618 # Check recipe
619 recipefile = get_bb_var('FILE', testrecipe)
620 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
621 checkvars = {}
622 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400623 checkvars['PV'] = '1.5+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000624 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500625 checkvars['SRCREV'] = checkrev
626 self._test_recipe_contents(recipefile, checkvars, [])
627
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500628 def test_devtool_add_fetch_simple(self):
629 # Fetch source from a remote URL, auto-detecting name
630 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
631 self.track_for_cleanup(tempdir)
632 testver = '1.6.0'
633 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
634 testrecipe = 'pv'
635 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
636 # Test devtool add
637 self.track_for_cleanup(self.workspacedir)
638 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
639 result = runCmd('devtool add %s' % url)
640 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
641 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
642 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
643 # Test devtool status
644 result = runCmd('devtool status')
645 self.assertIn(testrecipe, result.output)
646 self.assertIn(srcdir, result.output)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500647 # Check recipedevtool add
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500648 recipefile = get_bb_var('FILE', testrecipe)
649 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
650 checkvars = {}
651 checkvars['S'] = None
652 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
653 self._test_recipe_contents(recipefile, checkvars, [])
654
Andrew Geissler82c905d2020-04-13 13:39:40 -0500655 def test_devtool_add_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600656 collections = get_bb_var('BBFILE_COLLECTIONS').split()
657 if "openembedded-layer" not in collections:
658 self.skipTest("Test needs meta-oe for nodejs")
659
Andrew Geissler82c905d2020-04-13 13:39:40 -0500660 pn = 'savoirfairelinux-node-server-example'
661 pv = '1.0.0'
662 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
663 # Test devtool add
664 self.track_for_cleanup(self.workspacedir)
665 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
666 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
667 result = runCmd('devtool add \'%s\'' % url)
668 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
669 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
670 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
671 # Test devtool status
672 result = runCmd('devtool status')
673 self.assertIn(pn, result.output)
674 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
675 bitbake('%s -c cleansstate' % pn)
676 # Test devtool build
677 result = runCmd('devtool build %s' % pn)
678
Andrew Geissler615f2f12022-07-15 14:00:58 -0500679 def test_devtool_add_python_egg_requires(self):
680 # Fetch source
681 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
682 self.track_for_cleanup(tempdir)
683 testver = '0.14.0'
684 url = 'https://files.pythonhosted.org/packages/e9/9e/25d59f5043cf763833b2581c8027fa92342c4cf8ee523b498ecdf460c16d/uvicorn-%s.tar.gz' % testver
685 testrecipe = 'python3-uvicorn'
686 srcdir = os.path.join(tempdir, testrecipe)
687 # Test devtool add
688 self.track_for_cleanup(self.workspacedir)
689 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
690 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
691
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800692class DevtoolModifyTests(DevtoolBase):
693
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500694 def test_devtool_modify(self):
695 import oe.path
696
697 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
698 self.track_for_cleanup(tempdir)
699 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500700 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400701 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500702 result = runCmd('devtool modify mdadm -x %s' % tempdir)
703 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
704 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
705 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
706 self.assertTrue(matches, 'bbappend not created %s' % result.output)
707
708 # Test devtool status
709 result = runCmd('devtool status')
710 self.assertIn('mdadm', result.output)
711 self.assertIn(tempdir, result.output)
712 self._check_src_repo(tempdir)
713
714 bitbake('mdadm -C unpack')
715
716 def check_line(checkfile, expected, message, present=True):
717 # Check for $expected, on a line on its own, in checkfile.
718 with open(checkfile, 'r') as f:
719 if present:
720 self.assertIn(expected + '\n', f, message)
721 else:
722 self.assertNotIn(expected + '\n', f, message)
723
724 modfile = os.path.join(tempdir, 'mdadm.8.in')
725 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
726 pkgd = bb_vars['PKGD']
727 self.assertTrue(pkgd, 'Could not query PKGD variable')
728 mandir = bb_vars['mandir']
729 self.assertTrue(mandir, 'Could not query mandir variable')
730 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
731
732 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
733 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
734
735 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
736 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
737
738 bitbake('mdadm -c package')
739 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
740
741 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
742 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
743
744 bitbake('mdadm -c package')
745 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
746
747 result = runCmd('devtool reset mdadm')
748 result = runCmd('devtool status')
749 self.assertNotIn('mdadm', result.output)
750
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500751 def test_devtool_buildclean(self):
752 def assertFile(path, *paths):
753 f = os.path.join(path, *paths)
754 self.assertExists(f)
755 def assertNoFile(path, *paths):
756 f = os.path.join(path, *paths)
757 self.assertNotExists(f)
758
759 # Clean up anything in the workdir/sysroot/sstate cache
760 bitbake('mdadm m4 -c cleansstate')
761 # Try modifying a recipe
762 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
763 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
764 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
765 self.track_for_cleanup(tempdir_mdadm)
766 self.track_for_cleanup(tempdir_m4)
767 self.track_for_cleanup(builddir_m4)
768 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500769 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400770 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500771 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
772 try:
773 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
774 runCmd('devtool modify m4 -x %s' % tempdir_m4)
775 assertNoFile(tempdir_mdadm, 'mdadm')
776 assertNoFile(builddir_m4, 'src/m4')
777 result = bitbake('m4 -e')
778 result = bitbake('mdadm m4 -c compile')
779 self.assertEqual(result.status, 0)
780 assertFile(tempdir_mdadm, 'mdadm')
781 assertFile(builddir_m4, 'src/m4')
782 # Check that buildclean task exists and does call make clean
783 bitbake('mdadm m4 -c buildclean')
784 assertNoFile(tempdir_mdadm, 'mdadm')
785 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400786 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500787 bitbake('mdadm m4 -c compile')
788 assertFile(tempdir_mdadm, 'mdadm')
789 assertFile(builddir_m4, 'src/m4')
790 bitbake('mdadm m4 -c clean')
791 # Check that buildclean task is run before clean for B == S
792 assertNoFile(tempdir_mdadm, 'mdadm')
793 # Check that buildclean task is not run before clean for B != S
794 assertFile(builddir_m4, 'src/m4')
795 finally:
796 self.delete_recipeinc('m4')
797
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500798 def test_devtool_modify_invalid(self):
799 # Try modifying some recipes
800 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
801 self.track_for_cleanup(tempdir)
802 self.track_for_cleanup(self.workspacedir)
803 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
804
Andrew Geissler5199d832021-09-24 16:47:35 -0500805 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500806 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
807 result = runCmd('bitbake-layers show-recipes gcc-source*')
808 for line in result.output.splitlines():
809 # just match those lines that contain a real target
810 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
811 if m:
812 testrecipes.append(m.group('recipe'))
813 for testrecipe in testrecipes:
814 # Check it's a valid recipe
815 bitbake('%s -e' % testrecipe)
816 # devtool extract should fail
817 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
818 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
819 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
820 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
821 # devtool modify should fail
822 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
823 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
824 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
825
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500826 def test_devtool_modify_native(self):
827 # Check preconditions
828 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
829 # Try modifying some recipes
830 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
831 self.track_for_cleanup(tempdir)
832 self.track_for_cleanup(self.workspacedir)
833 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
834
835 bbclassextended = False
836 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500837 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500838 for testrecipe in testrecipes:
839 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
840 if not bbclassextended:
841 bbclassextended = checkextend
842 if not inheritnative:
843 inheritnative = not checkextend
844 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
845 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
846 result = runCmd('devtool build %s' % testrecipe)
847 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
848 result = runCmd('devtool reset %s' % testrecipe)
849 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
850
851 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
852 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 -0500853
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600854 def test_devtool_modify_localfiles_only(self):
855 # Check preconditions
856 testrecipe = 'base-files'
857 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
858 foundlocalonly = False
859 correct_symlink = False
860 for item in src_uri:
861 if item.startswith('file://'):
862 if '.patch' not in item:
863 foundlocalonly = True
864 else:
865 foundlocalonly = False
866 break
867 self.assertTrue(foundlocalonly, 'This test expects the %s recipe to fetch local files only and it seems that it no longer does' % testrecipe)
868 # Clean up anything in the workdir/sysroot/sstate cache
869 bitbake('%s -c cleansstate' % testrecipe)
870 # Try modifying a recipe
871 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
872 self.track_for_cleanup(tempdir)
873 self.track_for_cleanup(self.workspacedir)
874 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
875 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
876 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
877 srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
878 srclink = os.path.join(tempdir, 'share/dot.bashrc')
879 self.assertExists(srcfile, 'Extracted source could not be found')
880 if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
881 correct_symlink = True
882 self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500883
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600884 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
885 self.assertTrue(matches, 'bbappend not created')
886 # Test devtool status
887 result = runCmd('devtool status')
888 self.assertIn(testrecipe, result.output)
889 self.assertIn(tempdir, result.output)
890 # Try building
891 bitbake(testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500892
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500893 def test_devtool_modify_git(self):
894 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400895 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500896 src_uri = get_bb_var('SRC_URI', testrecipe)
897 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
898 # Clean up anything in the workdir/sysroot/sstate cache
899 bitbake('%s -c cleansstate' % testrecipe)
900 # Try modifying a recipe
901 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
902 self.track_for_cleanup(tempdir)
903 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500904 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400905 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500906 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400907 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500908 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 -0400909 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500910 self.assertTrue(matches, 'bbappend not created')
911 # Test devtool status
912 result = runCmd('devtool status')
913 self.assertIn(testrecipe, result.output)
914 self.assertIn(tempdir, result.output)
915 # Check git repo
916 self._check_src_repo(tempdir)
917 # Try building
918 bitbake(testrecipe)
919
Patrick Williamsf52e3dd2024-01-26 13:04:43 -0600920 def test_devtool_modify_git_no_extract(self):
921 # Check preconditions
922 testrecipe = 'psplash'
923 src_uri = get_bb_var('SRC_URI', testrecipe)
924 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
925 # Clean up anything in the workdir/sysroot/sstate cache
926 bitbake('%s -c cleansstate' % testrecipe)
927 # Try modifying a recipe
928 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
929 self.track_for_cleanup(tempdir)
930 self.track_for_cleanup(self.workspacedir)
931 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
932 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
933 result = runCmd('git clone https://git.yoctoproject.org/psplash %s && devtool modify -n %s %s' % (tempdir, testrecipe, tempdir))
934 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
935 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
936 self.assertTrue(matches, 'bbappend not created')
937 # Test devtool status
938 result = runCmd('devtool status')
939 self.assertIn(testrecipe, result.output)
940 self.assertIn(tempdir, result.output)
941
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500942 def test_devtool_modify_git_crates_subpath(self):
943 # This tests two things in devtool context:
944 # - that we support local git dependencies for cargo based recipe
945 # - that we support patches in SRC_URI when git url contains subpath parameter
946
947 # Check preconditions:
948 # recipe inherits cargo
949 # git:// uri with a subpath as the main package
950 # some crate:// in SRC_URI
951 # others git:// in SRC_URI
952 # cointains a patch
Patrick Williams169d7bc2024-01-05 11:33:25 -0600953 testrecipe = 'hello-rs'
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500954 bb_vars = get_bb_vars(['SRC_URI', 'FILE', 'WORKDIR', 'CARGO_HOME'], testrecipe)
955 recipefile = bb_vars['FILE']
956 workdir = bb_vars['WORKDIR']
957 cargo_home = bb_vars['CARGO_HOME']
958 src_uri = bb_vars['SRC_URI'].split()
959 self.assertTrue(src_uri[0].startswith('git://'),
960 'This test expects the %s recipe to have a git repo has its main uri' % testrecipe)
961 self.assertIn(';subpath=', src_uri[0],
962 'This test expects the %s recipe to have a git uri with subpath' % testrecipe)
963 self.assertTrue(any([uri.startswith('crate://') for uri in src_uri]),
964 'This test expects the %s recipe to have some crates in its src uris' % testrecipe)
Patrick Williams169d7bc2024-01-05 11:33:25 -0600965 self.assertGreaterEqual(sum(map(lambda x:x.startswith('git://'), src_uri)), 2,
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500966 'This test expects the %s recipe to have several git:// uris' % testrecipe)
967 self.assertTrue(any([uri.startswith('file://') and '.patch' in uri for uri in src_uri]),
968 'This test expects the %s recipe to have a patch in its src uris' % testrecipe)
969
Andrew Geissler028142b2023-05-05 11:29:21 -0500970 self._test_recipe_contents(recipefile, {}, ['ptest-cargo'])
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500971
972 # Clean up anything in the workdir/sysroot/sstate cache
973 bitbake('%s -c cleansstate' % testrecipe)
974 # Try modifying a recipe
975 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
976 self.track_for_cleanup(tempdir)
977 self.track_for_cleanup(self.workspacedir)
978 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
979 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
980 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
981 self.assertExists(os.path.join(tempdir, 'Cargo.toml'), 'Extracted source could not be found')
982 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
Patrick Williams169d7bc2024-01-05 11:33:25 -0600983 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500984 self.assertTrue(matches, 'bbappend not created')
985 # Test devtool status
986 result = runCmd('devtool status')
987 self.assertIn(testrecipe, result.output)
988 self.assertIn(tempdir, result.output)
989 # Check git repo
990 self._check_src_repo(tempdir)
991 # Check that the patch is correctly applied
992 # last commit message in the tree must contain
993 # %% original patch: <patchname>
994 # ..
995 patchname = None
996 for uri in src_uri:
997 if uri.startswith('file://') and '.patch' in uri:
998 patchname = uri.replace("file://", "").partition('.patch')[0] + '.patch'
999 self.assertIsNotNone(patchname)
1000 result = runCmd('git -C %s log -1' % tempdir)
1001 self.assertIn("%%%% original patch: %s" % patchname, result.output)
1002
1003 # Configure the recipe to check that the git dependencies are correctly patched in cargo config
1004 bitbake('-c configure %s' % testrecipe)
1005
1006 cargo_config_path = os.path.join(cargo_home, 'config')
1007 with open(cargo_config_path, "r") as f:
1008 cargo_config_contents = [line.strip('\n') for line in f.readlines()]
1009
1010 # Get back git dependencies of the recipe (ignoring the main one)
1011 # and check that they are all correctly patched to be fetched locally
1012 git_deps = [uri for uri in src_uri if uri.startswith("git://")][1:]
1013 for git_dep in git_deps:
1014 raw_url, _, raw_parms = git_dep.partition(";")
1015 parms = {}
1016 for parm in raw_parms.split(";"):
1017 name_parm, _, value_parm = parm.partition('=')
1018 parms[name_parm]=value_parm
1019 self.assertIn('protocol', parms, 'git dependencies uri should contain the "protocol" parameter')
1020 self.assertIn('name', parms, 'git dependencies uri should contain the "name" parameter')
1021 self.assertIn('destsuffix', parms, 'git dependencies uri should contain the "destsuffix" parameter')
1022 self.assertIn('type', parms, 'git dependencies uri should contain the "type" parameter')
1023 self.assertEqual(parms['type'], 'git-dependency', 'git dependencies uri should have "type=git-dependency"')
1024 raw_url = raw_url.replace("git://", '%s://' % parms['protocol'])
1025 patch_line = '[patch."%s"]' % raw_url
1026 path_patched = os.path.join(workdir, parms['destsuffix'])
1027 path_override_line = '%s = { path = "%s" }' % (parms['name'], path_patched)
1028 # Would have been better to use tomllib to read this file :/
1029 self.assertIn(patch_line, cargo_config_contents)
1030 self.assertIn(path_override_line, cargo_config_contents)
1031
1032 # Try to package the recipe
1033 bitbake('-c package_qa %s' % testrecipe)
1034
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001035 def test_devtool_modify_localfiles(self):
1036 # Check preconditions
1037 testrecipe = 'lighttpd'
1038 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
1039 foundlocal = False
1040 for item in src_uri:
1041 if item.startswith('file://') and '.patch' not in item:
1042 foundlocal = True
1043 break
1044 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
1045 # Clean up anything in the workdir/sysroot/sstate cache
1046 bitbake('%s -c cleansstate' % testrecipe)
1047 # Try modifying a recipe
1048 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1049 self.track_for_cleanup(tempdir)
1050 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001051 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001052 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001053 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1054 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
1055 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
1056 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
1057 self.assertTrue(matches, 'bbappend not created')
1058 # Test devtool status
1059 result = runCmd('devtool status')
1060 self.assertIn(testrecipe, result.output)
1061 self.assertIn(tempdir, result.output)
1062 # Try building
1063 bitbake(testrecipe)
1064
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001065 def test_devtool_modify_virtual(self):
1066 # Try modifying a virtual recipe
1067 virtrecipe = 'virtual/make'
1068 realrecipe = 'make'
1069 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1070 self.track_for_cleanup(tempdir)
1071 self.track_for_cleanup(self.workspacedir)
1072 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1073 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
1074 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1075 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
1076 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
1077 self.assertTrue(matches, 'bbappend not created %s' % result.output)
1078 # Test devtool status
1079 result = runCmd('devtool status')
1080 self.assertNotIn(virtrecipe, result.output)
1081 self.assertIn(realrecipe, result.output)
1082 # Check git repo
1083 self._check_src_repo(tempdir)
1084 # This is probably sufficient
1085
Andrew Geisslerf0343792020-11-18 10:42:21 -06001086 def test_devtool_modify_overrides(self):
1087 # Try modifying a recipe with patches in overrides
1088 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1089 self.track_for_cleanup(tempdir)
1090 self.track_for_cleanup(self.workspacedir)
1091 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1092 result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
1093
1094 self._check_src_repo(tempdir)
1095 source = os.path.join(tempdir, "source")
1096 def check(branch, expected):
1097 runCmd('git -C %s checkout %s' % (tempdir, branch))
1098 with open(source, "rt") as f:
1099 content = f.read()
1100 self.assertEquals(content, expected)
Patrick Williamsac13d5f2023-11-24 18:59:46 -06001101 if self.td["MACHINE"] == "qemux86":
1102 check('devtool', 'This is a test for qemux86\n')
1103 elif self.td["MACHINE"] == "qemuarm":
1104 check('devtool', 'This is a test for qemuarm\n')
1105 else:
1106 check('devtool', 'This is a test for something\n')
Andrew Geisslerf0343792020-11-18 10:42:21 -06001107 check('devtool-no-overrides', 'This is a test for something\n')
1108 check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
1109 check('devtool-override-qemux86', 'This is a test for qemux86\n')
1110
Patrick Williamsf52e3dd2024-01-26 13:04:43 -06001111 def test_devtool_modify_multiple_sources(self):
1112 # This test check that recipes fetching several sources can be used with devtool modify/build
1113 # Check preconditions
1114 testrecipe = 'bzip2'
1115 src_uri = get_bb_var('SRC_URI', testrecipe)
1116 src1 = 'https://' in src_uri
1117 src2 = 'git://' in src_uri
1118 self.assertTrue(src1 and src2, 'This test expects the %s recipe to fetch both a git source and a tarball and it seems that it no longer does' % testrecipe)
1119 # Clean up anything in the workdir/sysroot/sstate cache
1120 bitbake('%s -c cleansstate' % testrecipe)
1121 # Try modifying a recipe
1122 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1123 self.track_for_cleanup(tempdir)
1124 self.track_for_cleanup(self.workspacedir)
1125 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1126 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1127 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1128 self.assertEqual(result.status, 0, "Could not modify recipe %s. Output: %s" % (testrecipe, result.output))
1129 # Test devtool status
1130 result = runCmd('devtool status')
1131 self.assertIn(testrecipe, result.output)
1132 self.assertIn(tempdir, result.output)
1133 # Try building
1134 result = bitbake(testrecipe)
1135 self.assertEqual(result.status, 0, "Bitbake failed, exit code %s, output %s" % (result.status, result.output))
1136
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001137class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001138
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001139 def test_devtool_update_recipe(self):
1140 # Check preconditions
1141 testrecipe = 'minicom'
1142 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1143 recipefile = bb_vars['FILE']
1144 src_uri = bb_vars['SRC_URI']
1145 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1146 self._check_repo_status(os.path.dirname(recipefile), [])
1147 # First, modify a recipe
1148 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1149 self.track_for_cleanup(tempdir)
1150 self.track_for_cleanup(self.workspacedir)
1151 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1152 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1153 # We don't use -x here so that we test the behaviour of devtool modify without it
1154 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
1155 # Check git repo
1156 self._check_src_repo(tempdir)
1157 # Add a couple of commits
1158 # FIXME: this only tests adding, need to also test update and remove
1159 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
1160 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
1161 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1162 result = runCmd('git add devtool-new-file', cwd=tempdir)
1163 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1164 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1165 result = runCmd('devtool update-recipe %s' % testrecipe)
1166 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1167 ('??', '.*/0001-Change-the-README.patch$'),
1168 ('??', '.*/0002-Add-a-new-file.patch$')]
1169 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1170
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001171 def test_devtool_update_recipe_git(self):
1172 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001173 testrecipe = 'mtd-utils-selftest'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001174 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1175 recipefile = bb_vars['FILE']
1176 src_uri = bb_vars['SRC_URI']
1177 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1178 patches = []
1179 for entry in src_uri.split():
1180 if entry.startswith('file://') and entry.endswith('.patch'):
1181 patches.append(entry[7:].split(';')[0])
1182 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
1183 self._check_repo_status(os.path.dirname(recipefile), [])
1184 # First, modify a recipe
1185 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1186 self.track_for_cleanup(tempdir)
1187 self.track_for_cleanup(self.workspacedir)
1188 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1189 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1190 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1191 # Check git repo
1192 self._check_src_repo(tempdir)
1193 # Add a couple of commits
1194 # FIXME: this only tests adding, need to also test update and remove
1195 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
1196 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
1197 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1198 result = runCmd('git add devtool-new-file', cwd=tempdir)
1199 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1200 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1201 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
1202 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
1203 [(' D', '.*/%s$' % patch) for patch in patches]
1204 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1205
1206 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +00001207 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001208 srcurilines = src_uri.split()
1209 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
1210 srcurilines.append('"')
1211 removelines = ['SRCREV = ".*"'] + srcurilines
Andrew Geissler615f2f12022-07-15 14:00:58 -05001212 self._check_diff(result.output, addlines, removelines)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001213 # Now try with auto mode
1214 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
1215 result = runCmd('devtool update-recipe %s' % testrecipe)
1216 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
1217 topleveldir = result.output.strip()
1218 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
1219 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
1220 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
1221 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
1222 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1223
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001224 def test_devtool_update_recipe_append(self):
1225 # Check preconditions
1226 testrecipe = 'mdadm'
1227 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1228 recipefile = bb_vars['FILE']
1229 src_uri = bb_vars['SRC_URI']
1230 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1231 self._check_repo_status(os.path.dirname(recipefile), [])
1232 # First, modify a recipe
1233 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1234 tempsrcdir = os.path.join(tempdir, 'source')
1235 templayerdir = os.path.join(tempdir, 'layer')
1236 self.track_for_cleanup(tempdir)
1237 self.track_for_cleanup(self.workspacedir)
1238 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1239 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1240 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1241 # Check git repo
1242 self._check_src_repo(tempsrcdir)
1243 # Add a commit
1244 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
1245 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1246 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1247 # Create a temporary layer and add it to bblayers.conf
1248 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
1249 # Create the bbappend
1250 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1251 self.assertNotIn('WARNING:', result.output)
1252 # Check recipe is still clean
1253 self._check_repo_status(os.path.dirname(recipefile), [])
1254 # Check bbappend was created
1255 splitpath = os.path.dirname(recipefile).split(os.sep)
1256 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1257 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1258 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
1259 self.assertExists(patchfile, 'Patch file not created')
1260
1261 # Check bbappend contents
Patrick Williams213cb262021-08-07 19:21:33 -05001262 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001263 '\n',
1264 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
1265 '\n']
1266 with open(bbappendfile, 'r') as f:
1267 self.assertEqual(expectedlines, f.readlines())
1268
1269 # Check we can run it again and bbappend isn't modified
1270 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1271 with open(bbappendfile, 'r') as f:
1272 self.assertEqual(expectedlines, f.readlines())
1273 # Drop new commit and check patch gets deleted
1274 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1275 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1276 self.assertNotExists(patchfile, 'Patch file not deleted')
Patrick Williams213cb262021-08-07 19:21:33 -05001277 expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001278 '\n']
1279 with open(bbappendfile, 'r') as f:
1280 self.assertEqual(expectedlines2, f.readlines())
1281 # Put commit back and check we can run it if layer isn't in bblayers.conf
1282 os.remove(bbappendfile)
1283 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1284 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1285 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1286 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1287 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
1288 with open(bbappendfile, 'r') as f:
1289 self.assertEqual(expectedlines, f.readlines())
1290 # Deleting isn't expected to work under these circumstances
1291
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001292 def test_devtool_update_recipe_append_git(self):
1293 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001294 testrecipe = 'mtd-utils-selftest'
Andrew Geissler517393d2023-01-13 08:55:19 -06001295 bb_vars = get_bb_vars(['FILE', 'SRC_URI', 'LAYERSERIES_CORENAMES'], testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001296 recipefile = bb_vars['FILE']
1297 src_uri = bb_vars['SRC_URI']
Andrew Geissler517393d2023-01-13 08:55:19 -06001298 corenames = bb_vars['LAYERSERIES_CORENAMES']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001299 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1300 for entry in src_uri.split():
1301 if entry.startswith('git://'):
1302 git_uri = entry
1303 break
1304 self._check_repo_status(os.path.dirname(recipefile), [])
1305 # First, modify a recipe
1306 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1307 tempsrcdir = os.path.join(tempdir, 'source')
1308 templayerdir = os.path.join(tempdir, 'layer')
1309 self.track_for_cleanup(tempdir)
1310 self.track_for_cleanup(self.workspacedir)
1311 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1312 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1313 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1314 # Check git repo
1315 self._check_src_repo(tempsrcdir)
1316 # Add a commit
1317 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
1318 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1319 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1320 # Create a temporary layer
1321 os.makedirs(os.path.join(templayerdir, 'conf'))
1322 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
1323 f.write('BBPATH .= ":${LAYERDIR}"\n')
1324 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
1325 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
1326 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
1327 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
1328 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Andrew Geissler517393d2023-01-13 08:55:19 -06001329 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "%s"\n' % corenames)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001330 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
1331 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
1332 # Create the bbappend
1333 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1334 self.assertNotIn('WARNING:', result.output)
1335 # Check recipe is still clean
1336 self._check_repo_status(os.path.dirname(recipefile), [])
1337 # Check bbappend was created
1338 splitpath = os.path.dirname(recipefile).split(os.sep)
1339 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1340 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1341 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1342
1343 # Check bbappend contents
1344 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1345 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1346 '\n',
1347 'SRC_URI = "%s"\n' % git_uri,
1348 '\n'])
1349 with open(bbappendfile, 'r') as f:
1350 self.assertEqual(expectedlines, set(f.readlines()))
1351
1352 # Check we can run it again and bbappend isn't modified
1353 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1354 with open(bbappendfile, 'r') as f:
1355 self.assertEqual(expectedlines, set(f.readlines()))
1356 # Drop new commit and check SRCREV changes
1357 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1358 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1359 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1360 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1361 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1362 '\n',
1363 'SRC_URI = "%s"\n' % git_uri,
1364 '\n'])
1365 with open(bbappendfile, 'r') as f:
1366 self.assertEqual(expectedlines, set(f.readlines()))
1367 # Put commit back and check we can run it if layer isn't in bblayers.conf
1368 os.remove(bbappendfile)
1369 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1370 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1371 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1372 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1373 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1374 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1375 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1376 '\n',
1377 'SRC_URI = "%s"\n' % git_uri,
1378 '\n'])
1379 with open(bbappendfile, 'r') as f:
1380 self.assertEqual(expectedlines, set(f.readlines()))
1381 # Deleting isn't expected to work under these circumstances
1382
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001383 def test_devtool_update_recipe_local_files(self):
1384 """Check that local source files are copied over instead of patched"""
1385 testrecipe = 'makedevs'
1386 recipefile = get_bb_var('FILE', testrecipe)
1387 # Setup srctree for modifying the recipe
1388 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1389 self.track_for_cleanup(tempdir)
1390 self.track_for_cleanup(self.workspacedir)
1391 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1392 # (don't bother with cleaning the recipe on teardown, we won't be
1393 # building it)
1394 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1395 # Check git repo
1396 self._check_src_repo(tempdir)
1397 # Try building just to ensure we haven't broken that
1398 bitbake("%s" % testrecipe)
1399 # Edit / commit local source
1400 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1401 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1402 runCmd('echo "Bar" > new-file', cwd=tempdir)
1403 runCmd('git add new-file', cwd=tempdir)
1404 runCmd('git commit -m "Add new file"', cwd=tempdir)
1405 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1406 os.path.dirname(recipefile))
1407 runCmd('devtool update-recipe %s' % testrecipe)
1408 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1409 (' M', '.*/makedevs/makedevs.c$'),
1410 ('??', '.*/makedevs/new-local$'),
1411 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1412 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1413
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001414 def test_devtool_update_recipe_local_files_2(self):
1415 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001416 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001417 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001418 recipedir = os.path.dirname(recipefile)
1419 result = runCmd('git status --porcelain .', cwd=recipedir)
1420 if result.output.strip():
1421 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001422 # Setup srctree for modifying the recipe
1423 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1424 self.track_for_cleanup(tempdir)
1425 self.track_for_cleanup(self.workspacedir)
1426 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1427 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1428 # Check git repo
1429 self._check_src_repo(tempdir)
1430 # Add oe-local-files to Git
1431 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1432 runCmd('git add oe-local-files', cwd=tempdir)
1433 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1434 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001435 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001436 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001437 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001438 runCmd('git commit -m"Remove file"', cwd=tempdir)
1439 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1440 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1441 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1442 runCmd('echo "Gar" > new-file', cwd=tempdir)
1443 runCmd('git add new-file', cwd=tempdir)
1444 runCmd('git commit -m "Add new file"', cwd=tempdir)
1445 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1446 os.path.dirname(recipefile))
1447 # Checkout unmodified file to working copy -> devtool should still pick
1448 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001449 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001450 runCmd('devtool update-recipe %s' % testrecipe)
1451 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001452 (' M', '.*/file1$'),
1453 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001454 ('??', '.*/new-local$'),
1455 ('??', '.*/0001-Add-new-file.patch$')]
1456 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1457
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001458 def test_devtool_update_recipe_with_gitignore(self):
1459 # First, modify the recipe
1460 testrecipe = 'devtool-test-ignored'
1461 bb_vars = get_bb_vars(['FILE'], testrecipe)
1462 recipefile = bb_vars['FILE']
1463 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1464 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
1465 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1466 self.track_for_cleanup(tempdir)
1467 self.track_for_cleanup(self.workspacedir)
1468 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1469 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1470 result = runCmd('devtool modify %s' % testrecipe)
1471 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1472 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1473 # Check recipe got changed as expected
1474 with open(newpatchfile, 'r') as f:
1475 desiredlines = f.readlines()
1476 with open(patchfile, 'r') as f:
1477 newlines = f.readlines()
1478 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1479 # which changes the metadata subject which is added into the patch, but keep
1480 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1481 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1482 self.assertEqual(desiredlines[5:], newlines[5:])
1483
1484 def test_devtool_update_recipe_long_filename(self):
1485 # First, modify the recipe
1486 testrecipe = 'devtool-test-long-filename'
1487 bb_vars = get_bb_vars(['FILE'], testrecipe)
1488 recipefile = bb_vars['FILE']
1489 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1490 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1491 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1492 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1493 self.track_for_cleanup(tempdir)
1494 self.track_for_cleanup(self.workspacedir)
1495 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1496 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1497 result = runCmd('devtool modify %s' % testrecipe)
1498 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1499 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1500 # Check recipe got changed as expected
1501 with open(newpatchfile, 'r') as f:
1502 desiredlines = f.readlines()
1503 with open(patchfile, 'r') as f:
1504 newlines = f.readlines()
1505 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1506 # which changes the metadata subject which is added into the patch, but keep
1507 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1508 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1509 self.assertEqual(desiredlines[5:], newlines[5:])
1510
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001511 def test_devtool_update_recipe_local_files_3(self):
1512 # First, modify the recipe
1513 testrecipe = 'devtool-test-localonly'
1514 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1515 recipefile = bb_vars['FILE']
1516 src_uri = bb_vars['SRC_URI']
1517 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1518 self.track_for_cleanup(tempdir)
1519 self.track_for_cleanup(self.workspacedir)
1520 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1521 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1522 result = runCmd('devtool modify %s' % testrecipe)
1523 # Modify one file
1524 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1525 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1526 result = runCmd('devtool update-recipe %s' % testrecipe)
1527 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1528 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1529
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001530 def test_devtool_update_recipe_local_patch_gz(self):
1531 # First, modify the recipe
1532 testrecipe = 'devtool-test-patch-gz'
1533 if get_bb_var('DISTRO') == 'poky-tiny':
1534 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1535 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1536 recipefile = bb_vars['FILE']
1537 src_uri = bb_vars['SRC_URI']
1538 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1539 self.track_for_cleanup(tempdir)
1540 self.track_for_cleanup(self.workspacedir)
1541 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1542 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1543 result = runCmd('devtool modify %s' % testrecipe)
1544 # Modify one file
1545 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1546 runCmd('echo "Another line" >> README', cwd=srctree)
Patrick Williams169d7bc2024-01-05 11:33:25 -06001547 runCmd('git commit -a --amend --no-edit --no-verify', cwd=srctree)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001548 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1549 result = runCmd('devtool update-recipe %s' % testrecipe)
1550 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1551 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1552 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1553 result = runCmd('file %s' % patch_gz)
1554 if 'gzip compressed data' not in result.output:
1555 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1556
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001557 def test_devtool_update_recipe_local_files_subdir(self):
1558 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1559 # SRC_URI such that it overwrites a file that was in an archive that
1560 # was also in SRC_URI
1561 # First, modify the recipe
1562 testrecipe = 'devtool-test-subdir'
1563 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1564 recipefile = bb_vars['FILE']
1565 src_uri = bb_vars['SRC_URI']
1566 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1567 self.track_for_cleanup(tempdir)
1568 self.track_for_cleanup(self.workspacedir)
1569 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1570 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1571 result = runCmd('devtool modify %s' % testrecipe)
1572 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1573 self.assertExists(testfile, 'Extracted source could not be found')
1574 with open(testfile, 'r') as f:
1575 contents = f.read().rstrip()
1576 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1577 # Test devtool update-recipe without modifying any files
1578 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1579 result = runCmd('devtool update-recipe %s' % testrecipe)
1580 expected_status = []
1581 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1582
Andrew Geissler615f2f12022-07-15 14:00:58 -05001583 def test_devtool_finish_modify_git_subdir(self):
1584 # Check preconditions
1585 testrecipe = 'dos2unix'
Patrick Williams520786c2023-06-25 16:20:36 -05001586 self.append_config('ERROR_QA:remove:pn-dos2unix = "patch-status"\n')
Andrew Geissler615f2f12022-07-15 14:00:58 -05001587 bb_vars = get_bb_vars(['SRC_URI', 'S', 'WORKDIR', 'FILE'], testrecipe)
1588 self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe)
1589 workdir_git = '%s/git/' % bb_vars['WORKDIR']
1590 if not bb_vars['S'].startswith(workdir_git):
1591 self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe)
1592 subdir = bb_vars['S'].split(workdir_git, 1)[1]
1593 # Clean up anything in the workdir/sysroot/sstate cache
1594 bitbake('%s -c cleansstate' % testrecipe)
1595 # Try modifying a recipe
1596 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1597 self.track_for_cleanup(tempdir)
1598 self.track_for_cleanup(self.workspacedir)
1599 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1600 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1601 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1602 testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c')
1603 self.assertExists(testsrcfile, 'Extracted source could not be found')
1604 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
1605 self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo')
1606 # Check git repo
1607 self._check_src_repo(tempdir)
1608 # Modify file
1609 runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile)
1610 result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir)
1611 # Now try updating original recipe
1612 recipefile = bb_vars['FILE']
1613 recipedir = os.path.dirname(recipefile)
1614 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1615 result = runCmd('devtool update-recipe %s' % testrecipe)
1616 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1617 ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))]
1618 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1619 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
1620 removelines = ['SRC_URI = "git://.*"']
1621 addlines = [
1622 'SRC_URI = "git://.* \\\\',
1623 'file://0001-Add-a-comment.patch;patchdir=.. \\\\',
1624 '"'
1625 ]
1626 self._check_diff(result.output, addlines, removelines)
1627 # Put things back so we can run devtool finish on a different layer
1628 runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1629 # Run devtool finish
1630 res = re.search('recipes-.*', recipedir)
1631 self.assertTrue(res, 'Unable to find recipe subdirectory')
1632 recipesubdir = res[0]
1633 self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir))
1634 result = runCmd('devtool finish %s meta-selftest' % testrecipe)
1635 # Check bbappend file contents
1636 appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe)
1637 with open(appendfn, 'r') as f:
1638 appendlines = f.readlines()
1639 expected_appendlines = [
1640 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
1641 '\n',
1642 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n',
1643 '\n'
1644 ]
1645 self.assertEqual(appendlines, expected_appendlines)
1646 self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch'))
1647 # Try building
1648 bitbake('%s -c patch' % testrecipe)
1649
Patrick Williamsda295312023-12-05 16:48:56 -06001650 def test_devtool_git_submodules(self):
1651 # This tests if we can add a patch in a git submodule and extract it properly using devtool finish
1652 # Check preconditions
1653 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1654 self.track_for_cleanup(self.workspacedir)
1655 recipe = 'vulkan-samples'
1656 src_uri = get_bb_var('SRC_URI', recipe)
1657 self.assertIn('gitsm://', src_uri, 'This test expects the %s recipe to be a git recipe with submodules' % recipe)
1658 oldrecipefile = get_bb_var('FILE', recipe)
1659 recipedir = os.path.dirname(oldrecipefile)
1660 result = runCmd('git status --porcelain .', cwd=recipedir)
1661 if result.output.strip():
1662 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1663 self.assertIn('/meta/', recipedir)
1664 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1665 self.track_for_cleanup(tempdir)
1666 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1667 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1668 self.assertExists(os.path.join(tempdir, 'CMakeLists.txt'), 'Extracted source could not be found')
1669 # Test devtool status
1670 result = runCmd('devtool status')
1671 self.assertIn(recipe, result.output)
1672 self.assertIn(tempdir, result.output)
1673 # Modify a source file in a submodule, (grab the first one)
1674 result = runCmd('git submodule --quiet foreach \'echo $sm_path\'', cwd=tempdir)
1675 submodule = result.output.splitlines()[0]
1676 submodule_path = os.path.join(tempdir, submodule)
1677 runCmd('echo "#This is a first comment" >> testfile', cwd=submodule_path)
1678 result = runCmd('git status --porcelain . ', cwd=submodule_path)
1679 self.assertIn("testfile", result.output)
1680 runCmd('git add testfile; git commit -m "Adding a new file"', cwd=submodule_path)
1681
1682 # Try finish to the original layer
1683 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1684 runCmd('devtool finish -f %s meta' % recipe)
1685 result = runCmd('devtool status')
1686 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1687 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1688 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1689 ('??', '.*/.*-Adding-a-new-file.patch$')]
1690 self._check_repo_status(recipedir, expected_status)
1691 # Make sure the patch is added to the recipe with the correct "patchdir" option
1692 result = runCmd('git diff .', cwd=recipedir)
1693 addlines = [
1694 'file://0001-Adding-a-new-file.patch;patchdir=%s \\\\' % submodule
1695 ]
1696 self._check_diff(result.output, addlines, [])
Andrew Geissler615f2f12022-07-15 14:00:58 -05001697
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001698class DevtoolExtractTests(DevtoolBase):
1699
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001700 def test_devtool_extract(self):
1701 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1702 # Try devtool extract
1703 self.track_for_cleanup(tempdir)
1704 self.track_for_cleanup(self.workspacedir)
1705 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1706 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1707 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1708 self._check_src_repo(tempdir)
1709
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001710 def test_devtool_extract_virtual(self):
1711 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1712 # Try devtool extract
1713 self.track_for_cleanup(tempdir)
1714 self.track_for_cleanup(self.workspacedir)
1715 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1716 result = runCmd('devtool extract virtual/make %s' % tempdir)
1717 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1718 self._check_src_repo(tempdir)
1719
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001720 def test_devtool_reset_all(self):
1721 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1722 self.track_for_cleanup(tempdir)
1723 self.track_for_cleanup(self.workspacedir)
1724 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1725 testrecipe1 = 'mdadm'
1726 testrecipe2 = 'cronie'
1727 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1728 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1729 result = runCmd('devtool build %s' % testrecipe1)
1730 result = runCmd('devtool build %s' % testrecipe2)
1731 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1732 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1733 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1734 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1735 result = runCmd('devtool reset -a')
1736 self.assertIn(testrecipe1, result.output)
1737 self.assertIn(testrecipe2, result.output)
1738 result = runCmd('devtool status')
1739 self.assertNotIn(testrecipe1, result.output)
1740 self.assertNotIn(testrecipe2, result.output)
1741 matches1 = glob.glob(stampprefix1 + '*')
1742 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1743 matches2 = glob.glob(stampprefix2 + '*')
1744 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1745
Patrick Williams45852732022-04-02 08:58:32 -05001746 @OETestTag("runqemu")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001747 def test_devtool_deploy_target(self):
Andrew Geissler220dafd2023-10-04 10:18:08 -05001748 self._check_runqemu_prerequisites()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001749 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1750 # Definitions
1751 testrecipe = 'mdadm'
1752 testfile = '/sbin/mdadm'
1753 testimage = 'oe-selftest-image'
1754 testcommand = '/sbin/mdadm --help'
1755 # Build an image to run
1756 bitbake("%s qemu-native qemu-helper-native" % testimage)
1757 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1758 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1759 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1760 # Clean recipe so the first deploy will fail
1761 bitbake("%s -c clean" % testrecipe)
1762 # Try devtool modify
1763 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1764 self.track_for_cleanup(tempdir)
1765 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001766 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001767 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001768 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1769 # Test that deploy-target at this point fails (properly)
1770 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1771 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1772 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1773 result = runCmd('devtool build %s' % testrecipe)
1774 # First try a dry-run of deploy-target
1775 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1776 self.assertIn(' %s' % testfile, result.output)
1777 # Boot the image
1778 with runqemu(testimage) as qemu:
1779 # Now really test deploy-target
1780 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1781 # Run a test command to see if it was installed properly
1782 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1783 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1784 # Check if it deployed all of the files with the right ownership/perms
1785 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1786 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1787 installdir = bb_vars['D']
1788 fakerootenv = bb_vars['FAKEROOTENV']
1789 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001790 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001791 filelist1 = self._process_ls_output(result.output)
1792
1793 # Now look on the target
1794 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1795 self.track_for_cleanup(tempdir2)
1796 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1797 with open(tmpfilelist, 'w') as f:
1798 for line in filelist1:
1799 splitline = line.split()
1800 f.write(splitline[-1] + '\n')
1801 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1802 filelist2 = self._process_ls_output(result.output)
1803 filelist1.sort(key=lambda item: item.split()[-1])
1804 filelist2.sort(key=lambda item: item.split()[-1])
1805 self.assertEqual(filelist1, filelist2)
1806 # Test undeploy-target
1807 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1808 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1809 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1810
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001811 def test_devtool_build_image(self):
1812 """Test devtool build-image plugin"""
1813 # Check preconditions
1814 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1815 image = 'core-image-minimal'
1816 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001817 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001818 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001819 bitbake('%s -c clean' % image)
1820 # Add target and native recipes to workspace
1821 recipes = ['mdadm', 'parted-native']
1822 for recipe in recipes:
1823 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1824 self.track_for_cleanup(tempdir)
1825 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1826 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1827 # Try to build image
1828 result = runCmd('devtool build-image %s' % image)
1829 self.assertNotEqual(result, 0, 'devtool build-image failed')
1830 # Check if image contains expected packages
1831 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1832 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1833 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1834 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1835 for line in f:
1836 splitval = line.split()
1837 if splitval:
1838 pkg = splitval[0]
1839 if pkg in reqpkgs:
1840 reqpkgs.remove(pkg)
1841 if reqpkgs:
1842 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1843
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001844class DevtoolUpgradeTests(DevtoolBase):
1845
Patrick Williams45852732022-04-02 08:58:32 -05001846 def setUp(self):
1847 super().setUp()
1848 try:
1849 runCmd("git config --global user.name")
1850 runCmd("git config --global user.email")
1851 except:
1852 self.skip("Git user.name and user.email must be set")
1853
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001854 def test_devtool_upgrade(self):
1855 # Check preconditions
1856 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1857 self.track_for_cleanup(self.workspacedir)
1858 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1859 # Check parameters
1860 result = runCmd('devtool upgrade -h')
1861 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1862 self.assertIn(param, result.output)
1863 # For the moment, we are using a real recipe.
1864 recipe = 'devtool-upgrade-test1'
1865 version = '1.6.0'
1866 oldrecipefile = get_bb_var('FILE', recipe)
1867 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1868 self.track_for_cleanup(tempdir)
1869 # Check that recipe is not already under devtool control
1870 result = runCmd('devtool status')
1871 self.assertNotIn(recipe, result.output)
1872 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1873 # we are downgrading instead of upgrading.
1874 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1875 # Check if srctree at least is populated
1876 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1877 # Check new recipe subdirectory is present
1878 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1879 # Check new recipe file is present
1880 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1881 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1882 # Check devtool status and make sure recipe is present
1883 result = runCmd('devtool status')
1884 self.assertIn(recipe, result.output)
1885 self.assertIn(tempdir, result.output)
1886 # Check recipe got changed as expected
1887 with open(oldrecipefile + '.upgraded', 'r') as f:
1888 desiredlines = f.readlines()
1889 with open(newrecipefile, 'r') as f:
1890 newlines = f.readlines()
1891 self.assertEqual(desiredlines, newlines)
1892 # Check devtool reset recipe
1893 result = runCmd('devtool reset %s -n' % recipe)
1894 result = runCmd('devtool status')
1895 self.assertNotIn(recipe, result.output)
1896 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1897
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001898 def test_devtool_upgrade_git(self):
1899 # Check preconditions
1900 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1901 self.track_for_cleanup(self.workspacedir)
1902 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1903 recipe = 'devtool-upgrade-test2'
1904 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1905 oldrecipefile = get_bb_var('FILE', recipe)
1906 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1907 self.track_for_cleanup(tempdir)
1908 # Check that recipe is not already under devtool control
1909 result = runCmd('devtool status')
1910 self.assertNotIn(recipe, result.output)
1911 # Check upgrade
1912 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1913 # Check if srctree at least is populated
1914 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1915 # Check new recipe file is present
1916 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1917 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1918 # Check devtool status and make sure recipe is present
1919 result = runCmd('devtool status')
1920 self.assertIn(recipe, result.output)
1921 self.assertIn(tempdir, result.output)
1922 # Check recipe got changed as expected
1923 with open(oldrecipefile + '.upgraded', 'r') as f:
1924 desiredlines = f.readlines()
1925 with open(newrecipefile, 'r') as f:
1926 newlines = f.readlines()
1927 self.assertEqual(desiredlines, newlines)
1928 # Check devtool reset recipe
1929 result = runCmd('devtool reset %s -n' % recipe)
1930 result = runCmd('devtool status')
1931 self.assertNotIn(recipe, result.output)
1932 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1933
Patrick Williams169d7bc2024-01-05 11:33:25 -06001934 def test_devtool_upgrade_drop_md5sum(self):
1935 # Check preconditions
1936 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1937 self.track_for_cleanup(self.workspacedir)
1938 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1939 # For the moment, we are using a real recipe.
1940 recipe = 'devtool-upgrade-test3'
1941 version = '1.6.0'
1942 oldrecipefile = get_bb_var('FILE', recipe)
1943 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1944 self.track_for_cleanup(tempdir)
1945 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1946 # we are downgrading instead of upgrading.
1947 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1948 # Check new recipe file is present
1949 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1950 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1951 # Check recipe got changed as expected
1952 with open(oldrecipefile + '.upgraded', 'r') as f:
1953 desiredlines = f.readlines()
1954 with open(newrecipefile, 'r') as f:
1955 newlines = f.readlines()
1956 self.assertEqual(desiredlines, newlines)
1957
1958 def test_devtool_upgrade_all_checksums(self):
1959 # Check preconditions
1960 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1961 self.track_for_cleanup(self.workspacedir)
1962 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1963 # For the moment, we are using a real recipe.
1964 recipe = 'devtool-upgrade-test4'
1965 version = '1.6.0'
1966 oldrecipefile = get_bb_var('FILE', recipe)
1967 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1968 self.track_for_cleanup(tempdir)
1969 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1970 # we are downgrading instead of upgrading.
1971 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1972 # Check new recipe file is present
1973 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1974 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1975 # Check recipe got changed as expected
1976 with open(oldrecipefile + '.upgraded', 'r') as f:
1977 desiredlines = f.readlines()
1978 with open(newrecipefile, 'r') as f:
1979 newlines = f.readlines()
1980 self.assertEqual(desiredlines, newlines)
1981
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001982 def test_devtool_layer_plugins(self):
1983 """Test that devtool can use plugins from other layers.
1984
1985 This test executes the selftest-reverse command from meta-selftest."""
1986
1987 self.track_for_cleanup(self.workspacedir)
1988 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1989
1990 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1991 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1992 self.assertEqual(result.output, s[::-1])
1993
1994 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1995 dstdir = basedstdir
1996 self.assertExists(dstdir)
1997 for p in paths:
1998 dstdir = os.path.join(dstdir, p)
1999 if not os.path.exists(dstdir):
Patrick Williams169d7bc2024-01-05 11:33:25 -06002000 try:
2001 os.makedirs(dstdir)
2002 except PermissionError:
2003 return False
2004 except OSError as e:
2005 if e.errno == errno.EROFS:
2006 return False
2007 else:
2008 raise e
Andrew Geissler475cb722020-07-10 16:00:51 -05002009 if p == "lib":
2010 # Can race with other tests
2011 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
2012 else:
2013 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002014 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
2015 if srcfile != dstfile:
Patrick Williams169d7bc2024-01-05 11:33:25 -06002016 try:
2017 shutil.copy(srcfile, dstfile)
2018 except PermissionError:
2019 return False
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002020 self.track_for_cleanup(dstfile)
Patrick Williams169d7bc2024-01-05 11:33:25 -06002021 return True
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002022
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002023 def test_devtool_load_plugin(self):
2024 """Test that devtool loads only the first found plugin in BBPATH."""
2025
2026 self.track_for_cleanup(self.workspacedir)
2027 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
2028
2029 devtool = runCmd("which devtool")
2030 fromname = runCmd("devtool --quiet pluginfile")
2031 srcfile = fromname.output
2032 bbpath = get_bb_var('BBPATH')
2033 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
2034 plugincontent = []
2035 with open(srcfile) as fh:
2036 plugincontent = fh.readlines()
2037 try:
2038 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
Patrick Williams169d7bc2024-01-05 11:33:25 -06002039 searchpath = [
2040 path for path in searchpath
2041 if self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
2042 ]
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002043 result = runCmd("devtool --quiet count")
2044 self.assertEqual(result.output, '1')
2045 result = runCmd("devtool --quiet multiloaded")
2046 self.assertEqual(result.output, "no")
2047 for path in searchpath:
2048 result = runCmd("devtool --quiet bbdir")
Patrick Williams169d7bc2024-01-05 11:33:25 -06002049 self.assertEqual(os.path.realpath(result.output), os.path.realpath(path))
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002050 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
2051 finally:
2052 with open(srcfile, 'w') as fh:
2053 fh.writelines(plugincontent)
2054
2055 def _setup_test_devtool_finish_upgrade(self):
2056 # Check preconditions
2057 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
2058 self.track_for_cleanup(self.workspacedir)
2059 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
2060 # Use a "real" recipe from meta-selftest
2061 recipe = 'devtool-upgrade-test1'
2062 oldversion = '1.5.3'
2063 newversion = '1.6.0'
2064 oldrecipefile = get_bb_var('FILE', recipe)
2065 recipedir = os.path.dirname(oldrecipefile)
2066 result = runCmd('git status --porcelain .', cwd=recipedir)
2067 if result.output.strip():
2068 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
2069 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2070 self.track_for_cleanup(tempdir)
2071 # Check that recipe is not already under devtool control
2072 result = runCmd('devtool status')
2073 self.assertNotIn(recipe, result.output)
2074 # Do the upgrade
2075 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
2076 # Check devtool status and make sure recipe is present
2077 result = runCmd('devtool status')
2078 self.assertIn(recipe, result.output)
2079 self.assertIn(tempdir, result.output)
2080 # Make a change to the source
2081 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
2082 result = runCmd('git status --porcelain', cwd=tempdir)
2083 self.assertIn('M src/pv/number.c', result.output)
2084 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
2085 # Check if patch is there
2086 recipedir = os.path.dirname(oldrecipefile)
2087 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
2088 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05002089 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002090 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05002091 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
2092 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002093
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002094 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05002095 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002096 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
2097 self.assertIn('/meta-selftest/', recipedir)
2098 # Try finish to the original layer
2099 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2100 result = runCmd('devtool finish %s meta-selftest' % recipe)
2101 result = runCmd('devtool status')
2102 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2103 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2104 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
2105 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05002106 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 -05002107 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
2108 newdir = os.path.join(recipedir, recipe + '-' + newversion)
2109 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
2110 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 -05002111 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 -05002112 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 -05002113 with open(newrecipefile, 'r') as f:
2114 newcontent = f.read()
2115 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
2116 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
2117 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
2118 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
2119
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002120
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002121 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05002122 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002123 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
2124 self.assertIn('/meta-selftest/', recipedir)
2125 # Try finish to a different layer - should create a bbappend
2126 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
2127 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2128 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
2129 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
2130 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
2131 self.track_for_cleanup(newrecipedir)
2132 result = runCmd('devtool finish %s oe-core' % recipe)
2133 result = runCmd('devtool status')
2134 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2135 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2136 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
2137 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05002138 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002139 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
2140 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
2141 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 -05002142 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 -05002143 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 -05002144 with open(newrecipefile, 'r') as f:
2145 newcontent = f.read()
2146 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
2147 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
2148 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
2149 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 -05002150
2151 def _setup_test_devtool_finish_modify(self):
2152 # Check preconditions
2153 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
2154 # Try modifying a recipe
2155 self.track_for_cleanup(self.workspacedir)
2156 recipe = 'mdadm'
2157 oldrecipefile = get_bb_var('FILE', recipe)
2158 recipedir = os.path.dirname(oldrecipefile)
2159 result = runCmd('git status --porcelain .', cwd=recipedir)
2160 if result.output.strip():
2161 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
2162 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2163 self.track_for_cleanup(tempdir)
2164 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
2165 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
2166 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2167 # Test devtool status
2168 result = runCmd('devtool status')
2169 self.assertIn(recipe, result.output)
2170 self.assertIn(tempdir, result.output)
2171 # Make a change to the source
2172 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
2173 result = runCmd('git status --porcelain', cwd=tempdir)
2174 self.assertIn('M maps.c', result.output)
2175 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
2176 for entry in os.listdir(recipedir):
2177 filesdir = os.path.join(recipedir, entry)
2178 if os.path.isdir(filesdir):
2179 break
2180 else:
2181 self.fail('Unable to find recipe files directory for %s' % recipe)
2182 return recipe, oldrecipefile, recipedir, filesdir
2183
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002184 def test_devtool_finish_modify_origlayer(self):
2185 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
2186 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
2187 self.assertIn('/meta/', recipedir)
2188 # Try finish to the original layer
2189 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2190 result = runCmd('devtool finish %s meta' % recipe)
2191 result = runCmd('devtool status')
2192 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2193 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2194 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
2195 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
2196 self._check_repo_status(recipedir, expected_status)
2197
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002198 def test_devtool_finish_modify_otherlayer(self):
2199 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
2200 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
2201 self.assertIn('/meta/', recipedir)
2202 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
2203 appenddir = os.path.join(get_test_layer(), relpth)
2204 self.track_for_cleanup(appenddir)
2205 # Try finish to the original layer
2206 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2207 result = runCmd('devtool finish %s meta-selftest' % recipe)
2208 result = runCmd('devtool status')
2209 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2210 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2211 result = runCmd('git status --porcelain .', cwd=recipedir)
2212 if result.output.strip():
2213 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
2214 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
2215 recipefn = recipefn.split('_')[0] + '_%'
2216 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
2217 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
2218 newdir = os.path.join(appenddir, recipe)
2219 files = os.listdir(newdir)
2220 foundpatch = None
2221 for fn in files:
2222 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
2223 foundpatch = fn
2224 if not foundpatch:
2225 self.fail('No patch file created next to bbappend')
2226 files.remove(foundpatch)
2227 if files:
2228 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
2229
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002230 def test_devtool_rename(self):
2231 # Check preconditions
2232 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
2233 self.track_for_cleanup(self.workspacedir)
2234 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
2235
2236 # First run devtool add
2237 # We already have this recipe in OE-Core, but that doesn't matter
2238 recipename = 'i2c-tools'
2239 recipever = '3.1.2'
2240 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
2241 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
2242 def add_recipe():
2243 result = runCmd('devtool add %s' % url)
2244 self.assertExists(recipefile, 'Expected recipe file not created')
2245 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
2246 checkvars = {}
2247 checkvars['S'] = None
2248 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2249 self._test_recipe_contents(recipefile, checkvars, [])
2250 add_recipe()
2251 # Now rename it - change both name and version
2252 newrecipename = 'mynewrecipe'
2253 newrecipever = '456'
2254 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
2255 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
2256 self.assertExists(newrecipefile, 'Recipe file not renamed')
2257 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2258 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
2259 self.assertExists(newsrctree, 'Source directory not renamed')
2260 checkvars = {}
2261 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
2262 checkvars['SRC_URI'] = url
2263 self._test_recipe_contents(newrecipefile, checkvars, [])
2264 # Try again - change just name this time
2265 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002266 add_recipe()
2267 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
2268 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
2269 self.assertExists(newrecipefile, 'Recipe file not renamed')
2270 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2271 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
2272 checkvars = {}
2273 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
2274 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2275 self._test_recipe_contents(newrecipefile, checkvars, [])
2276 # Try again - change just version this time
2277 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002278 add_recipe()
2279 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
2280 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
2281 self.assertExists(newrecipefile, 'Recipe file not renamed')
2282 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
2283 checkvars = {}
2284 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
2285 checkvars['SRC_URI'] = url
2286 self._test_recipe_contents(newrecipefile, checkvars, [])
2287
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002288 def test_devtool_virtual_kernel_modify(self):
2289 """
2290 Summary: The purpose of this test case is to verify that
2291 devtool modify works correctly when building
2292 the kernel.
2293 Dependencies: NA
2294 Steps: 1. Build kernel with bitbake.
2295 2. Save the config file generated.
2296 3. Clean the environment.
2297 4. Use `devtool modify virtual/kernel` to validate following:
2298 4.1 The source is checked out correctly.
2299 4.2 The resulting configuration is the same as
2300 what was get on step 2.
2301 4.3 The Kernel can be build correctly.
2302 4.4 Changes made on the source are reflected on the
2303 subsequent builds.
2304 4.5 Changes on the configuration are reflected on the
2305 subsequent builds
2306 Expected: devtool modify is able to checkout the source of the kernel
2307 and modification to the source and configurations are reflected
2308 when building the kernel.
Patrick Williams45852732022-04-02 08:58:32 -05002309 """
2310 kernel_provider = self.td['PREFERRED_PROVIDER_virtual/kernel']
2311
Andrew Geissler82c905d2020-04-13 13:39:40 -05002312 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002313 bitbake('%s -c clean' % kernel_provider)
2314 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2315 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
2316 self.track_for_cleanup(tempdir)
2317 self.track_for_cleanup(tempdir_cfg)
2318 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002319 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04002320 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002321 #Step 1
2322 #Here is just generated the config file instead of all the kernel to optimize the
2323 #time of executing this test case.
2324 bitbake('%s -c configure' % kernel_provider)
2325 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
2326 #Step 2
2327 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
2328 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
2329
2330 tmpconfig = os.path.join(tempdir_cfg, '.config')
2331 #Step 3
2332 bitbake('%s -c clean' % kernel_provider)
2333 #Step 4.1
2334 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
2335 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2336 #Step 4.2
2337 configfile = os.path.join(tempdir,'.config')
Patrick Williams45852732022-04-02 08:58:32 -05002338 runCmd('diff %s %s' % (tmpconfig, configfile))
2339
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002340 #Step 4.3
2341 #NOTE: virtual/kernel is mapped to kernel_provider
Patrick Williams45852732022-04-02 08:58:32 -05002342 runCmd('devtool build %s' % kernel_provider)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002343 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
2344 self.assertExists(kernelfile, 'Kernel was not build correctly')
2345
2346 #Modify the kernel source
Patrick Williams45852732022-04-02 08:58:32 -05002347 modfile = os.path.join(tempdir, 'init/version.c')
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002348 # Moved to uts.h in 6.1 onwards
2349 modfile2 = os.path.join(tempdir, 'include/linux/uts.h')
2350 runCmd("sed -i 's/Linux/LiNuX/g' %s %s" % (modfile, modfile2))
Patrick Williams45852732022-04-02 08:58:32 -05002351
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002352 #Modify the configuration
Patrick Williams45852732022-04-02 08:58:32 -05002353 codeconfigfile = os.path.join(tempdir, '.config.new')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002354 modconfopt = "CONFIG_SG_POOL=n"
Patrick Williams45852732022-04-02 08:58:32 -05002355 runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
2356
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002357 #Build again kernel with devtool
Patrick Williams45852732022-04-02 08:58:32 -05002358 runCmd('devtool build %s' % kernel_provider)
2359
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002360 #Step 4.4
Patrick Williams45852732022-04-02 08:58:32 -05002361 runCmd("grep '%s' %s" % ('LiNuX', kernelfile))
2362
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002363 #Step 4.5
Patrick Williams45852732022-04-02 08:58:32 -05002364 runCmd("grep %s %s" % (modconfopt, codeconfigfile))