blob: ab58971fec73e681bbe47873f679d180d6760e98 [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
Patrick Williams92b42cb2022-09-03 06:53:57 -05002# Copyright OpenEmbedded Contributors
3#
Brad Bishopc342db32019-05-15 21:57:59 -04004# SPDX-License-Identifier: MIT
5#
6
Brad Bishopd7bf8c12018-02-25 22:55:05 -05007import os
8import re
9import shutil
10import tempfile
11import glob
12import fnmatch
Patrick Williamse760df82023-05-26 11:10:49 -050013import unittest
Brad Bishopd7bf8c12018-02-25 22:55:05 -050014
Brad Bishopd7bf8c12018-02-25 22:55:05 -050015from oeqa.selftest.case import OESelftestTestCase
16from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer
17from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer
Patrick Williams45852732022-04-02 08:58:32 -050018from oeqa.core.decorator import OETestTag
Brad Bishopd7bf8c12018-02-25 22:55:05 -050019
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080020oldmetapath = None
21
22def setUpModule():
23 import bb.utils
24
25 global templayerdir
26 templayerdir = tempfile.mkdtemp(prefix='devtoolqa')
27 corecopydir = os.path.join(templayerdir, 'core-copy')
28 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
29 edited_layers = []
Patrick Williamsac13d5f2023-11-24 18:59:46 -060030 # make sure user doesn't have a local workspace
31 result = runCmd('bitbake-layers show-layers')
32 assert "workspacelayer" not in result.output, "Devtool test suite cannot be run with a local workspace directory"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080033
34 # We need to take a copy of the meta layer so we can modify it and not
35 # have any races against other tests that might be running in parallel
36 # however things like COREBASE mean that you can't just copy meta, you
37 # need the whole repository.
38 def bblayers_edit_cb(layerpath, canonical_layerpath):
39 global oldmetapath
40 if not canonical_layerpath.endswith('/'):
41 # This helps us match exactly when we're using this path later
42 canonical_layerpath += '/'
43 if not edited_layers and canonical_layerpath.endswith('/meta/'):
44 canonical_layerpath = os.path.realpath(canonical_layerpath) + '/'
45 edited_layers.append(layerpath)
46 oldmetapath = os.path.realpath(layerpath)
Patrick Williamse760df82023-05-26 11:10:49 -050047
48 # when downloading poky from tar.gz some tests will be skipped (BUG 12389)
49 try:
50 runCmd('git rev-parse --is-inside-work-tree', cwd=canonical_layerpath)
51 except:
52 raise unittest.SkipTest("devtool tests require folder to be a git repo")
53
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080054 result = runCmd('git rev-parse --show-toplevel', cwd=canonical_layerpath)
55 oldreporoot = result.output.rstrip()
56 newmetapath = os.path.join(corecopydir, os.path.relpath(oldmetapath, oldreporoot))
57 runCmd('git clone %s %s' % (oldreporoot, corecopydir), cwd=templayerdir)
58 # Now we need to copy any modified files
59 # You might ask "why not just copy the entire tree instead of
60 # cloning and doing this?" - well, the problem with that is
61 # TMPDIR or an equally large subdirectory might exist
62 # under COREBASE and we don't want to copy that, so we have
63 # to be selective.
64 result = runCmd('git status --porcelain', cwd=oldreporoot)
65 for line in result.output.splitlines():
66 if line.startswith(' M ') or line.startswith('?? '):
67 relpth = line.split()[1]
68 pth = os.path.join(oldreporoot, relpth)
69 if pth.startswith(canonical_layerpath):
70 if relpth.endswith('/'):
71 destdir = os.path.join(corecopydir, relpth)
Andrew Geisslerc3d88e42020-10-02 09:45:00 -050072 # avoid race condition by not copying .pyc files YPBZ#13421,13803
Andrew Geisslerd1e89492021-02-12 15:35:20 -060073 shutil.copytree(pth, destdir, ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080074 else:
75 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
76 bb.utils.mkdirhier(destdir)
77 shutil.copy2(pth, destdir)
78 return newmetapath
79 else:
80 return layerpath
81 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
82
83def tearDownModule():
84 if oldmetapath:
85 edited_layers = []
86 def bblayers_edit_cb(layerpath, canonical_layerpath):
87 if not edited_layers and canonical_layerpath.endswith('/meta'):
88 edited_layers.append(layerpath)
89 return oldmetapath
90 else:
91 return layerpath
92 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
93 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
94 shutil.rmtree(templayerdir)
95
Andrew Geissler595f6302022-01-24 19:11:47 +000096class DevtoolTestCase(OESelftestTestCase):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080097
98 def setUp(self):
99 """Test case setup function"""
Andrew Geissler595f6302022-01-24 19:11:47 +0000100 super(DevtoolTestCase, self).setUp()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800101 self.workspacedir = os.path.join(self.builddir, 'workspace')
102 self.assertTrue(not os.path.exists(self.workspacedir),
103 'This test cannot be run with a workspace directory '
104 'under the build directory')
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800105
106 def _check_src_repo(self, repo_dir):
107 """Check srctree git repository"""
108 self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')),
109 'git repository for external source tree not found')
110 result = runCmd('git status --porcelain', cwd=repo_dir)
111 self.assertEqual(result.output.strip(), "",
112 'Created git repo is not clean')
113 result = runCmd('git symbolic-ref HEAD', cwd=repo_dir)
114 self.assertEqual(result.output.strip(), "refs/heads/devtool",
115 'Wrong branch in git repo')
116
117 def _check_repo_status(self, repo_dir, expected_status):
118 """Check the worktree status of a repository"""
119 result = runCmd('git status . --porcelain',
120 cwd=repo_dir)
121 for line in result.output.splitlines():
122 for ind, (f_status, fn_re) in enumerate(expected_status):
123 if re.match(fn_re, line[3:]):
124 if f_status != line[:2]:
125 self.fail('Unexpected status in line: %s' % line)
126 expected_status.pop(ind)
127 break
128 else:
129 self.fail('Unexpected modified file in line: %s' % line)
130 if expected_status:
131 self.fail('Missing file changes: %s' % expected_status)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500132
133 def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
134 with open(recipefile, 'r') as f:
135 invar = None
136 invalue = None
Brad Bishop6dbb3162019-11-25 09:41:34 -0500137 inherits = set()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500138 for line in f:
139 var = None
140 if invar:
141 value = line.strip().strip('"')
142 if value.endswith('\\'):
143 invalue += ' ' + value[:-1].strip()
144 continue
145 else:
146 invalue += ' ' + value.strip()
147 var = invar
148 value = invalue
149 invar = None
150 elif '=' in line:
151 splitline = line.split('=', 1)
152 var = splitline[0].rstrip()
153 value = splitline[1].strip().strip('"')
154 if value.endswith('\\'):
155 invalue = value[:-1].strip()
156 invar = var
157 continue
158 elif line.startswith('inherit '):
Brad Bishop6dbb3162019-11-25 09:41:34 -0500159 inherits.update(line.split()[1:])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500160
161 if var and var in checkvars:
162 needvalue = checkvars.pop(var)
163 if needvalue is None:
164 self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value))
165 if isinstance(needvalue, set):
166 if var == 'LICENSE':
167 value = set(value.split(' & '))
168 else:
169 value = set(value.split())
170 self.assertEqual(value, needvalue, 'values for %s do not match' % var)
171
172
173 missingvars = {}
174 for var, value in checkvars.items():
175 if value is not None:
176 missingvars[var] = value
177 self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars)
178
179 for inherit in checkinherits:
180 self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
181
182 def _check_bbappend(self, testrecipe, recipefile, appenddir):
183 result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
184 resultlines = result.output.splitlines()
185 inrecipe = False
186 bbappends = []
187 bbappendfile = None
188 for line in resultlines:
189 if inrecipe:
190 if line.startswith(' '):
191 bbappends.append(line.strip())
192 else:
193 break
194 elif line == '%s:' % os.path.basename(recipefile):
195 inrecipe = True
196 self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
197 for bbappend in bbappends:
198 if bbappend.startswith(appenddir):
199 bbappendfile = bbappend
200 break
201 else:
202 self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
203 return bbappendfile
204
205 def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
206 create_temp_layer(templayerdir, templayername, priority, recipepathspec)
207 if addlayer:
208 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
209 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
210
211 def _process_ls_output(self, output):
212 """
213 Convert ls -l output to a format we can reasonably compare from one context
214 to another (e.g. from host to target)
215 """
216 filelist = []
217 for line in output.splitlines():
218 splitline = line.split()
219 if len(splitline) < 8:
220 self.fail('_process_ls_output: invalid output line: %s' % line)
221 # Remove trailing . on perms
222 splitline[0] = splitline[0].rstrip('.')
223 # Remove leading . on paths
224 splitline[-1] = splitline[-1].lstrip('.')
225 # Drop fields we don't want to compare
226 del splitline[7]
227 del splitline[6]
228 del splitline[5]
229 del splitline[4]
230 del splitline[1]
231 filelist.append(' '.join(splitline))
232 return filelist
233
Andrew Geissler615f2f12022-07-15 14:00:58 -0500234 def _check_diff(self, diffoutput, addlines, removelines):
235 """Check output from 'git diff' matches expectation"""
236 remaining_addlines = addlines[:]
237 remaining_removelines = removelines[:]
238 for line in diffoutput.splitlines():
239 if line.startswith('+++') or line.startswith('---'):
240 continue
241 elif line.startswith('+'):
242 matched = False
243 for item in addlines:
244 if re.match(item, line[1:].strip()):
245 matched = True
246 remaining_addlines.remove(item)
247 break
248 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
249 elif line.startswith('-'):
250 matched = False
251 for item in removelines:
252 if re.match(item, line[1:].strip()):
253 matched = True
254 remaining_removelines.remove(item)
255 break
256 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
257 if remaining_addlines:
258 self.fail('Expected added lines not found: %s' % remaining_addlines)
259 if remaining_removelines:
260 self.fail('Expected removed lines not found: %s' % remaining_removelines)
261
Andrew Geissler220dafd2023-10-04 10:18:08 -0500262 def _check_runqemu_prerequisites(self):
263 """Check runqemu is available
264
265 Whilst some tests would seemingly be better placed as a runtime test,
266 unfortunately the runtime tests run under bitbake and you can't run
267 devtool within bitbake (since devtool needs to run bitbake itself).
268 Additionally we are testing build-time functionality as well, so
269 really this has to be done as an oe-selftest test.
270 """
271 machine = get_bb_var('MACHINE')
272 if not machine.startswith('qemu'):
273 self.skipTest('This test only works with qemu machines')
274 if not os.path.exists('/etc/runqemu-nosudo'):
275 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
276 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
277 if result.status != 0:
278 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
279 if result.status != 0:
280 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
281 for line in result.output.splitlines():
282 if line.startswith('tap'):
283 break
284 else:
285 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
286
Patrick Williams92b42cb2022-09-03 06:53:57 -0500287 def _test_devtool_add_git_url(self, git_url, version, pn, resulting_src_uri):
288 self.track_for_cleanup(self.workspacedir)
289 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
290 result = runCmd('devtool add --version %s %s %s' % (version, pn, git_url))
291 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
292 # Check the recipe name is correct
293 recipefile = get_bb_var('FILE', pn)
294 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
295 self.assertIn(recipefile, result.output)
296 # Test devtool status
297 result = runCmd('devtool status')
298 self.assertIn(pn, result.output)
299 self.assertIn(recipefile, result.output)
300 checkvars = {}
301 checkvars['SRC_URI'] = resulting_src_uri
302 self._test_recipe_contents(recipefile, checkvars, [])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500303
Andrew Geissler595f6302022-01-24 19:11:47 +0000304class DevtoolBase(DevtoolTestCase):
305
306 @classmethod
307 def setUpClass(cls):
308 super(DevtoolBase, cls).setUpClass()
309 bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
310 cls.original_sstate = bb_vars['SSTATE_DIR']
311 cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
312 cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
313 cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
314 % cls.original_sstate)
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500315 cls.sstate_conf += ('BB_HASHSERVE_UPSTREAM = "hashserv.yocto.io:8687"\n')
Andrew Geissler595f6302022-01-24 19:11:47 +0000316
317 @classmethod
318 def tearDownClass(cls):
319 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
320 runCmd('rm -rf %s' % cls.devtool_sstate)
321 super(DevtoolBase, cls).tearDownClass()
322
323 def setUp(self):
324 """Test case setup function"""
325 super(DevtoolBase, self).setUp()
326 self.append_config(self.sstate_conf)
327
328
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500329class DevtoolTests(DevtoolBase):
330
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500331 def test_create_workspace(self):
332 # Check preconditions
333 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400334 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 -0400335 # remove conf/devtool.conf to avoid it corrupting tests
336 devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
337 self.track_for_cleanup(devtoolconf)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500338 # Try creating a workspace layer with a specific path
339 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
340 self.track_for_cleanup(tempdir)
341 result = runCmd('devtool create-workspace %s' % tempdir)
342 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
343 result = runCmd('bitbake-layers show-layers')
344 self.assertIn(tempdir, result.output)
345 # Try creating a workspace layer with the default path
346 self.track_for_cleanup(self.workspacedir)
347 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
348 result = runCmd('devtool create-workspace')
349 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
350 result = runCmd('bitbake-layers show-layers')
351 self.assertNotIn(tempdir, result.output)
352 self.assertIn(self.workspacedir, result.output)
353
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800354class DevtoolAddTests(DevtoolBase):
355
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500356 def test_devtool_add(self):
357 # Fetch source
358 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
359 self.track_for_cleanup(tempdir)
360 pn = 'pv'
361 pv = '1.5.3'
Andrew Geissler09209ee2020-12-13 08:44:15 -0600362 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500363 result = runCmd('wget %s' % url, cwd=tempdir)
364 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
365 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
366 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
367 # Test devtool add
368 self.track_for_cleanup(self.workspacedir)
369 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
370 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
371 result = runCmd('devtool add %s %s' % (pn, srcdir))
372 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
373 # Test devtool status
374 result = runCmd('devtool status')
375 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
376 self.assertIn(recipepath, result.output)
377 self.assertIn(srcdir, result.output)
378 # Test devtool find-recipe
379 result = runCmd('devtool -q find-recipe %s' % pn)
380 self.assertEqual(recipepath, result.output.strip())
381 # Test devtool edit-recipe
382 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
383 self.assertEqual('123 %s' % recipepath, result.output.strip())
384 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
385 bitbake('%s -c cleansstate' % pn)
386 # Test devtool build
387 result = runCmd('devtool build %s' % pn)
388 bb_vars = get_bb_vars(['D', 'bindir'], pn)
389 installdir = bb_vars['D']
390 self.assertTrue(installdir, 'Could not query installdir variable')
391 bindir = bb_vars['bindir']
392 self.assertTrue(bindir, 'Could not query bindir variable')
393 if bindir[0] == '/':
394 bindir = bindir[1:]
395 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
396
Andrew Geissler8f840682023-07-21 09:09:43 -0500397 def test_devtool_add_binary(self):
398 # Create a binary package containing a known test file
399 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
400 self.track_for_cleanup(tempdir)
401 pn = 'tst-bin'
402 pv = '1.0'
403 test_file_dir = "var/lib/%s/" % pn
404 test_file_name = "test_file"
405 test_file_content = "TEST CONTENT"
406 test_file_package_root = os.path.join(tempdir, pn)
407 test_file_dir_full = os.path.join(test_file_package_root, test_file_dir)
408 bb.utils.mkdirhier(test_file_dir_full)
409 with open(os.path.join(test_file_dir_full, test_file_name), "w") as f:
410 f.write(test_file_content)
411 bin_package_path = os.path.join(tempdir, "%s.tar.gz" % pn)
412 runCmd("tar czf %s -C %s ." % (bin_package_path, test_file_package_root))
413
414 # Test devtool add -b on the binary package
415 self.track_for_cleanup(self.workspacedir)
416 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
417 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
418 result = runCmd('devtool add -b %s %s' % (pn, bin_package_path))
419 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
420
421 # Build the resulting recipe
422 result = runCmd('devtool build %s' % pn)
423 installdir = get_bb_var('D', pn)
424 self.assertTrue(installdir, 'Could not query installdir variable')
425
426 # Check that a known file from the binary package has indeed been installed
427 self.assertTrue(os.path.isfile(os.path.join(installdir, test_file_dir, test_file_name)), '%s not found in D' % test_file_name)
428
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500429 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800430 # We need dbus built so that DEPENDS recognition works
431 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500432 # Fetch source from a remote URL, but do it outside of devtool
433 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
434 self.track_for_cleanup(tempdir)
435 pn = 'dbus-wait'
436 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
437 # We choose an https:// git URL here to check rewriting the URL works
438 url = 'https://git.yoctoproject.org/git/dbus-wait'
439 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
440 # instead of the directory name
441 result = runCmd('git clone %s noname' % url, cwd=tempdir)
442 srcdir = os.path.join(tempdir, 'noname')
443 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
444 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
445 # Test devtool add
446 self.track_for_cleanup(self.workspacedir)
447 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
448 # Don't specify a name since we should be able to auto-detect it
449 result = runCmd('devtool add %s' % srcdir)
450 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
451 # Check the recipe name is correct
452 recipefile = get_bb_var('FILE', pn)
453 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
454 self.assertIn(recipefile, result.output)
455 # Test devtool status
456 result = runCmd('devtool status')
457 self.assertIn(pn, result.output)
458 self.assertIn(srcdir, result.output)
459 self.assertIn(recipefile, result.output)
460 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000461 checkvars['LICENSE'] = 'GPL-2.0-only'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500462 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
463 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400464 checkvars['PV'] = '0.1+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000465 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500466 checkvars['SRCREV'] = srcrev
467 checkvars['DEPENDS'] = set(['dbus'])
468 self._test_recipe_contents(recipefile, checkvars, [])
469
Patrick Williams92b42cb2022-09-03 06:53:57 -0500470 def test_devtool_add_git_style1(self):
471 version = 'v3.1.0'
472 pn = 'mbedtls'
473 # this will trigger reformat_git_uri with branch parameter in url
474 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https'"
475 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https"
476 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
477
478 def test_devtool_add_git_style2(self):
479 version = 'v3.1.0'
480 pn = 'mbedtls'
481 # this will trigger reformat_git_uri with branch parameter in url
482 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;protocol=https'"
483 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;protocol=https;branch=master"
484 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
485
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500486 def test_devtool_add_library(self):
487 # Fetch source
488 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
489 self.track_for_cleanup(tempdir)
490 version = '1.1'
491 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
492 result = runCmd('wget %s' % url, cwd=tempdir)
493 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
494 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
495 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
496 # Test devtool add (and use -V so we test that too)
497 self.track_for_cleanup(self.workspacedir)
498 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
499 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
500 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
501 # Test devtool status
502 result = runCmd('devtool status')
503 self.assertIn('libftdi', result.output)
504 self.assertIn(srcdir, result.output)
505 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
506 bitbake('libftdi -c cleansstate')
507 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
508 # There's also the matter of it installing cmake files to a path we don't
509 # normally cover, which triggers the installed-vs-shipped QA test we have
510 # within do_package
511 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
512 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
513 with open(recipefile, 'a') as f:
Patrick Williams213cb262021-08-07 19:21:33 -0500514 f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500515 # We don't have the ability to pick up this dependency automatically yet...
516 f.write('\nDEPENDS += "libusb1"\n')
517 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
518 # Test devtool build
519 result = runCmd('devtool build libftdi')
520 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
521 staging_libdir = bb_vars['TESTLIBOUTPUT']
522 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
523 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)
524 # Test devtool reset
525 stampprefix = bb_vars['STAMP']
526 result = runCmd('devtool reset libftdi')
527 result = runCmd('devtool status')
528 self.assertNotIn('libftdi', result.output)
529 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
530 matches = glob.glob(stampprefix + '*')
531 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
532 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
533
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500534 def test_devtool_add_fetch(self):
535 # Fetch source
536 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
537 self.track_for_cleanup(tempdir)
538 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400539 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500540 testrecipe = 'python-markupsafe'
541 srcdir = os.path.join(tempdir, testrecipe)
542 # Test devtool add
543 self.track_for_cleanup(self.workspacedir)
544 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
545 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
546 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
547 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
548 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
549 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
550 # Test devtool status
551 result = runCmd('devtool status')
552 self.assertIn(testrecipe, result.output)
553 self.assertIn(srcdir, result.output)
554 # Check recipe
555 recipefile = get_bb_var('FILE', testrecipe)
556 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
557 checkvars = {}
558 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
559 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
560 self._test_recipe_contents(recipefile, checkvars, [])
561 # Try with version specified
562 result = runCmd('devtool reset -n %s' % testrecipe)
563 shutil.rmtree(srcdir)
564 fakever = '1.9'
565 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
566 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
567 # Test devtool status
568 result = runCmd('devtool status')
569 self.assertIn(testrecipe, result.output)
570 self.assertIn(srcdir, result.output)
571 # Check recipe
572 recipefile = get_bb_var('FILE', testrecipe)
573 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
574 checkvars = {}
575 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
576 checkvars['SRC_URI'] = url
577 self._test_recipe_contents(recipefile, checkvars, [])
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600578
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500579 def test_devtool_add_fetch_git(self):
580 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
581 self.track_for_cleanup(tempdir)
582 url = 'gitsm://git.yoctoproject.org/mraa'
Andrew Geissler595f6302022-01-24 19:11:47 +0000583 url_branch = '%s;branch=master' % url
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500584 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
585 testrecipe = 'mraa'
586 srcdir = os.path.join(tempdir, testrecipe)
587 # Test devtool add
588 self.track_for_cleanup(self.workspacedir)
589 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
590 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
591 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
592 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
593 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
594 # Test devtool status
595 result = runCmd('devtool status')
596 self.assertIn(testrecipe, result.output)
597 self.assertIn(srcdir, result.output)
598 # Check recipe
599 recipefile = get_bb_var('FILE', testrecipe)
600 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
601 checkvars = {}
602 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400603 checkvars['PV'] = '1.0+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000604 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500605 checkvars['SRCREV'] = '${AUTOREV}'
606 self._test_recipe_contents(recipefile, checkvars, [])
607 # Try with revision and version specified
608 result = runCmd('devtool reset -n %s' % testrecipe)
609 shutil.rmtree(srcdir)
610 url_rev = '%s;rev=%s' % (url, checkrev)
611 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
612 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
613 # Test devtool status
614 result = runCmd('devtool status')
615 self.assertIn(testrecipe, result.output)
616 self.assertIn(srcdir, result.output)
617 # Check recipe
618 recipefile = get_bb_var('FILE', testrecipe)
619 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
620 checkvars = {}
621 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400622 checkvars['PV'] = '1.5+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000623 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500624 checkvars['SRCREV'] = checkrev
625 self._test_recipe_contents(recipefile, checkvars, [])
626
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500627 def test_devtool_add_fetch_simple(self):
628 # Fetch source from a remote URL, auto-detecting name
629 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
630 self.track_for_cleanup(tempdir)
631 testver = '1.6.0'
632 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
633 testrecipe = 'pv'
634 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
635 # Test devtool add
636 self.track_for_cleanup(self.workspacedir)
637 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
638 result = runCmd('devtool add %s' % url)
639 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
640 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
641 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
642 # Test devtool status
643 result = runCmd('devtool status')
644 self.assertIn(testrecipe, result.output)
645 self.assertIn(srcdir, result.output)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500646 # Check recipedevtool add
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500647 recipefile = get_bb_var('FILE', testrecipe)
648 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
649 checkvars = {}
650 checkvars['S'] = None
651 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
652 self._test_recipe_contents(recipefile, checkvars, [])
653
Andrew Geissler82c905d2020-04-13 13:39:40 -0500654 def test_devtool_add_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600655 collections = get_bb_var('BBFILE_COLLECTIONS').split()
656 if "openembedded-layer" not in collections:
657 self.skipTest("Test needs meta-oe for nodejs")
658
Andrew Geissler82c905d2020-04-13 13:39:40 -0500659 pn = 'savoirfairelinux-node-server-example'
660 pv = '1.0.0'
661 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
662 # Test devtool add
663 self.track_for_cleanup(self.workspacedir)
664 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
665 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
666 result = runCmd('devtool add \'%s\'' % url)
667 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
668 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
669 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
670 # Test devtool status
671 result = runCmd('devtool status')
672 self.assertIn(pn, result.output)
673 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
674 bitbake('%s -c cleansstate' % pn)
675 # Test devtool build
676 result = runCmd('devtool build %s' % pn)
677
Andrew Geissler615f2f12022-07-15 14:00:58 -0500678 def test_devtool_add_python_egg_requires(self):
679 # Fetch source
680 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
681 self.track_for_cleanup(tempdir)
682 testver = '0.14.0'
683 url = 'https://files.pythonhosted.org/packages/e9/9e/25d59f5043cf763833b2581c8027fa92342c4cf8ee523b498ecdf460c16d/uvicorn-%s.tar.gz' % testver
684 testrecipe = 'python3-uvicorn'
685 srcdir = os.path.join(tempdir, testrecipe)
686 # Test devtool add
687 self.track_for_cleanup(self.workspacedir)
688 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
689 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
690
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800691class DevtoolModifyTests(DevtoolBase):
692
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500693 def test_devtool_modify(self):
694 import oe.path
695
696 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
697 self.track_for_cleanup(tempdir)
698 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500699 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400700 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500701 result = runCmd('devtool modify mdadm -x %s' % tempdir)
702 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
703 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
704 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
705 self.assertTrue(matches, 'bbappend not created %s' % result.output)
706
707 # Test devtool status
708 result = runCmd('devtool status')
709 self.assertIn('mdadm', result.output)
710 self.assertIn(tempdir, result.output)
711 self._check_src_repo(tempdir)
712
713 bitbake('mdadm -C unpack')
714
715 def check_line(checkfile, expected, message, present=True):
716 # Check for $expected, on a line on its own, in checkfile.
717 with open(checkfile, 'r') as f:
718 if present:
719 self.assertIn(expected + '\n', f, message)
720 else:
721 self.assertNotIn(expected + '\n', f, message)
722
723 modfile = os.path.join(tempdir, 'mdadm.8.in')
724 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
725 pkgd = bb_vars['PKGD']
726 self.assertTrue(pkgd, 'Could not query PKGD variable')
727 mandir = bb_vars['mandir']
728 self.assertTrue(mandir, 'Could not query mandir variable')
729 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
730
731 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
732 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
733
734 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
735 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
736
737 bitbake('mdadm -c package')
738 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
739
740 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
741 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
742
743 bitbake('mdadm -c package')
744 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
745
746 result = runCmd('devtool reset mdadm')
747 result = runCmd('devtool status')
748 self.assertNotIn('mdadm', result.output)
749
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500750 def test_devtool_buildclean(self):
751 def assertFile(path, *paths):
752 f = os.path.join(path, *paths)
753 self.assertExists(f)
754 def assertNoFile(path, *paths):
755 f = os.path.join(path, *paths)
756 self.assertNotExists(f)
757
758 # Clean up anything in the workdir/sysroot/sstate cache
759 bitbake('mdadm m4 -c cleansstate')
760 # Try modifying a recipe
761 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
762 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
763 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
764 self.track_for_cleanup(tempdir_mdadm)
765 self.track_for_cleanup(tempdir_m4)
766 self.track_for_cleanup(builddir_m4)
767 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500768 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400769 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500770 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
771 try:
772 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
773 runCmd('devtool modify m4 -x %s' % tempdir_m4)
774 assertNoFile(tempdir_mdadm, 'mdadm')
775 assertNoFile(builddir_m4, 'src/m4')
776 result = bitbake('m4 -e')
777 result = bitbake('mdadm m4 -c compile')
778 self.assertEqual(result.status, 0)
779 assertFile(tempdir_mdadm, 'mdadm')
780 assertFile(builddir_m4, 'src/m4')
781 # Check that buildclean task exists and does call make clean
782 bitbake('mdadm m4 -c buildclean')
783 assertNoFile(tempdir_mdadm, 'mdadm')
784 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400785 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500786 bitbake('mdadm m4 -c compile')
787 assertFile(tempdir_mdadm, 'mdadm')
788 assertFile(builddir_m4, 'src/m4')
789 bitbake('mdadm m4 -c clean')
790 # Check that buildclean task is run before clean for B == S
791 assertNoFile(tempdir_mdadm, 'mdadm')
792 # Check that buildclean task is not run before clean for B != S
793 assertFile(builddir_m4, 'src/m4')
794 finally:
795 self.delete_recipeinc('m4')
796
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500797 def test_devtool_modify_invalid(self):
798 # Try modifying some recipes
799 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
800 self.track_for_cleanup(tempdir)
801 self.track_for_cleanup(self.workspacedir)
802 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
803
Andrew Geissler5199d832021-09-24 16:47:35 -0500804 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500805 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
806 result = runCmd('bitbake-layers show-recipes gcc-source*')
807 for line in result.output.splitlines():
808 # just match those lines that contain a real target
809 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
810 if m:
811 testrecipes.append(m.group('recipe'))
812 for testrecipe in testrecipes:
813 # Check it's a valid recipe
814 bitbake('%s -e' % testrecipe)
815 # devtool extract should fail
816 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
817 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
818 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
819 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
820 # devtool modify should fail
821 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
822 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
823 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
824
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500825 def test_devtool_modify_native(self):
826 # Check preconditions
827 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
828 # Try modifying some recipes
829 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
830 self.track_for_cleanup(tempdir)
831 self.track_for_cleanup(self.workspacedir)
832 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
833
834 bbclassextended = False
835 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500836 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500837 for testrecipe in testrecipes:
838 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
839 if not bbclassextended:
840 bbclassextended = checkextend
841 if not inheritnative:
842 inheritnative = not checkextend
843 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
844 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
845 result = runCmd('devtool build %s' % testrecipe)
846 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
847 result = runCmd('devtool reset %s' % testrecipe)
848 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
849
850 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
851 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 -0500852
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600853 def test_devtool_modify_localfiles_only(self):
854 # Check preconditions
855 testrecipe = 'base-files'
856 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
857 foundlocalonly = False
858 correct_symlink = False
859 for item in src_uri:
860 if item.startswith('file://'):
861 if '.patch' not in item:
862 foundlocalonly = True
863 else:
864 foundlocalonly = False
865 break
866 self.assertTrue(foundlocalonly, 'This test expects the %s recipe to fetch local files only and it seems that it no longer does' % testrecipe)
867 # Clean up anything in the workdir/sysroot/sstate cache
868 bitbake('%s -c cleansstate' % testrecipe)
869 # Try modifying a recipe
870 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
871 self.track_for_cleanup(tempdir)
872 self.track_for_cleanup(self.workspacedir)
873 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
874 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
875 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
876 srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
877 srclink = os.path.join(tempdir, 'share/dot.bashrc')
878 self.assertExists(srcfile, 'Extracted source could not be found')
879 if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
880 correct_symlink = True
881 self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500882
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600883 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
884 self.assertTrue(matches, 'bbappend not created')
885 # Test devtool status
886 result = runCmd('devtool status')
887 self.assertIn(testrecipe, result.output)
888 self.assertIn(tempdir, result.output)
889 # Try building
890 bitbake(testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500891
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500892 def test_devtool_modify_git(self):
893 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400894 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500895 src_uri = get_bb_var('SRC_URI', testrecipe)
896 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
897 # Clean up anything in the workdir/sysroot/sstate cache
898 bitbake('%s -c cleansstate' % testrecipe)
899 # Try modifying a recipe
900 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
901 self.track_for_cleanup(tempdir)
902 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500903 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400904 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500905 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400906 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500907 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 -0400908 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500909 self.assertTrue(matches, 'bbappend not created')
910 # Test devtool status
911 result = runCmd('devtool status')
912 self.assertIn(testrecipe, result.output)
913 self.assertIn(tempdir, result.output)
914 # Check git repo
915 self._check_src_repo(tempdir)
916 # Try building
917 bitbake(testrecipe)
918
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500919 def test_devtool_modify_git_crates_subpath(self):
920 # This tests two things in devtool context:
921 # - that we support local git dependencies for cargo based recipe
922 # - that we support patches in SRC_URI when git url contains subpath parameter
923
924 # Check preconditions:
925 # recipe inherits cargo
926 # git:// uri with a subpath as the main package
927 # some crate:// in SRC_URI
928 # others git:// in SRC_URI
929 # cointains a patch
930 testrecipe = 'zvariant'
931 bb_vars = get_bb_vars(['SRC_URI', 'FILE', 'WORKDIR', 'CARGO_HOME'], testrecipe)
932 recipefile = bb_vars['FILE']
933 workdir = bb_vars['WORKDIR']
934 cargo_home = bb_vars['CARGO_HOME']
935 src_uri = bb_vars['SRC_URI'].split()
936 self.assertTrue(src_uri[0].startswith('git://'),
937 'This test expects the %s recipe to have a git repo has its main uri' % testrecipe)
938 self.assertIn(';subpath=', src_uri[0],
939 'This test expects the %s recipe to have a git uri with subpath' % testrecipe)
940 self.assertTrue(any([uri.startswith('crate://') for uri in src_uri]),
941 'This test expects the %s recipe to have some crates in its src uris' % testrecipe)
942 self.assertGreater(sum(map(lambda x:x.startswith('git://'), src_uri)), 2,
943 'This test expects the %s recipe to have several git:// uris' % testrecipe)
944 self.assertTrue(any([uri.startswith('file://') and '.patch' in uri for uri in src_uri]),
945 'This test expects the %s recipe to have a patch in its src uris' % testrecipe)
946
Andrew Geissler028142b2023-05-05 11:29:21 -0500947 self._test_recipe_contents(recipefile, {}, ['ptest-cargo'])
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500948
949 # Clean up anything in the workdir/sysroot/sstate cache
950 bitbake('%s -c cleansstate' % testrecipe)
951 # Try modifying a recipe
952 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
953 self.track_for_cleanup(tempdir)
954 self.track_for_cleanup(self.workspacedir)
955 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
956 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
957 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
958 self.assertExists(os.path.join(tempdir, 'Cargo.toml'), 'Extracted source could not be found')
959 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
960 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'zvariant_*.bbappend'))
961 self.assertTrue(matches, 'bbappend not created')
962 # Test devtool status
963 result = runCmd('devtool status')
964 self.assertIn(testrecipe, result.output)
965 self.assertIn(tempdir, result.output)
966 # Check git repo
967 self._check_src_repo(tempdir)
968 # Check that the patch is correctly applied
969 # last commit message in the tree must contain
970 # %% original patch: <patchname>
971 # ..
972 patchname = None
973 for uri in src_uri:
974 if uri.startswith('file://') and '.patch' in uri:
975 patchname = uri.replace("file://", "").partition('.patch')[0] + '.patch'
976 self.assertIsNotNone(patchname)
977 result = runCmd('git -C %s log -1' % tempdir)
978 self.assertIn("%%%% original patch: %s" % patchname, result.output)
979
980 # Configure the recipe to check that the git dependencies are correctly patched in cargo config
981 bitbake('-c configure %s' % testrecipe)
982
983 cargo_config_path = os.path.join(cargo_home, 'config')
984 with open(cargo_config_path, "r") as f:
985 cargo_config_contents = [line.strip('\n') for line in f.readlines()]
986
987 # Get back git dependencies of the recipe (ignoring the main one)
988 # and check that they are all correctly patched to be fetched locally
989 git_deps = [uri for uri in src_uri if uri.startswith("git://")][1:]
990 for git_dep in git_deps:
991 raw_url, _, raw_parms = git_dep.partition(";")
992 parms = {}
993 for parm in raw_parms.split(";"):
994 name_parm, _, value_parm = parm.partition('=')
995 parms[name_parm]=value_parm
996 self.assertIn('protocol', parms, 'git dependencies uri should contain the "protocol" parameter')
997 self.assertIn('name', parms, 'git dependencies uri should contain the "name" parameter')
998 self.assertIn('destsuffix', parms, 'git dependencies uri should contain the "destsuffix" parameter')
999 self.assertIn('type', parms, 'git dependencies uri should contain the "type" parameter')
1000 self.assertEqual(parms['type'], 'git-dependency', 'git dependencies uri should have "type=git-dependency"')
1001 raw_url = raw_url.replace("git://", '%s://' % parms['protocol'])
1002 patch_line = '[patch."%s"]' % raw_url
1003 path_patched = os.path.join(workdir, parms['destsuffix'])
1004 path_override_line = '%s = { path = "%s" }' % (parms['name'], path_patched)
1005 # Would have been better to use tomllib to read this file :/
1006 self.assertIn(patch_line, cargo_config_contents)
1007 self.assertIn(path_override_line, cargo_config_contents)
1008
1009 # Try to package the recipe
1010 bitbake('-c package_qa %s' % testrecipe)
1011
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001012 def test_devtool_modify_localfiles(self):
1013 # Check preconditions
1014 testrecipe = 'lighttpd'
1015 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
1016 foundlocal = False
1017 for item in src_uri:
1018 if item.startswith('file://') and '.patch' not in item:
1019 foundlocal = True
1020 break
1021 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
1022 # Clean up anything in the workdir/sysroot/sstate cache
1023 bitbake('%s -c cleansstate' % testrecipe)
1024 # Try modifying a recipe
1025 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1026 self.track_for_cleanup(tempdir)
1027 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001028 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001029 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001030 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1031 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
1032 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
1033 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
1034 self.assertTrue(matches, 'bbappend not created')
1035 # Test devtool status
1036 result = runCmd('devtool status')
1037 self.assertIn(testrecipe, result.output)
1038 self.assertIn(tempdir, result.output)
1039 # Try building
1040 bitbake(testrecipe)
1041
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001042 def test_devtool_modify_virtual(self):
1043 # Try modifying a virtual recipe
1044 virtrecipe = 'virtual/make'
1045 realrecipe = 'make'
1046 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1047 self.track_for_cleanup(tempdir)
1048 self.track_for_cleanup(self.workspacedir)
1049 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1050 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
1051 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1052 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
1053 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
1054 self.assertTrue(matches, 'bbappend not created %s' % result.output)
1055 # Test devtool status
1056 result = runCmd('devtool status')
1057 self.assertNotIn(virtrecipe, result.output)
1058 self.assertIn(realrecipe, result.output)
1059 # Check git repo
1060 self._check_src_repo(tempdir)
1061 # This is probably sufficient
1062
Andrew Geisslerf0343792020-11-18 10:42:21 -06001063 def test_devtool_modify_overrides(self):
1064 # Try modifying a recipe with patches in overrides
1065 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1066 self.track_for_cleanup(tempdir)
1067 self.track_for_cleanup(self.workspacedir)
1068 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1069 result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
1070
1071 self._check_src_repo(tempdir)
1072 source = os.path.join(tempdir, "source")
1073 def check(branch, expected):
1074 runCmd('git -C %s checkout %s' % (tempdir, branch))
1075 with open(source, "rt") as f:
1076 content = f.read()
1077 self.assertEquals(content, expected)
Patrick Williamsac13d5f2023-11-24 18:59:46 -06001078 if self.td["MACHINE"] == "qemux86":
1079 check('devtool', 'This is a test for qemux86\n')
1080 elif self.td["MACHINE"] == "qemuarm":
1081 check('devtool', 'This is a test for qemuarm\n')
1082 else:
1083 check('devtool', 'This is a test for something\n')
Andrew Geisslerf0343792020-11-18 10:42:21 -06001084 check('devtool-no-overrides', 'This is a test for something\n')
1085 check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
1086 check('devtool-override-qemux86', 'This is a test for qemux86\n')
1087
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001088class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001089
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001090 def test_devtool_update_recipe(self):
1091 # Check preconditions
1092 testrecipe = 'minicom'
1093 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1094 recipefile = bb_vars['FILE']
1095 src_uri = bb_vars['SRC_URI']
1096 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1097 self._check_repo_status(os.path.dirname(recipefile), [])
1098 # First, modify a recipe
1099 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1100 self.track_for_cleanup(tempdir)
1101 self.track_for_cleanup(self.workspacedir)
1102 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1103 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1104 # We don't use -x here so that we test the behaviour of devtool modify without it
1105 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
1106 # Check git repo
1107 self._check_src_repo(tempdir)
1108 # Add a couple of commits
1109 # FIXME: this only tests adding, need to also test update and remove
1110 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
1111 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
1112 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1113 result = runCmd('git add devtool-new-file', cwd=tempdir)
1114 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1115 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1116 result = runCmd('devtool update-recipe %s' % testrecipe)
1117 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1118 ('??', '.*/0001-Change-the-README.patch$'),
1119 ('??', '.*/0002-Add-a-new-file.patch$')]
1120 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1121
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001122 def test_devtool_update_recipe_git(self):
1123 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001124 testrecipe = 'mtd-utils-selftest'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001125 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1126 recipefile = bb_vars['FILE']
1127 src_uri = bb_vars['SRC_URI']
1128 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1129 patches = []
1130 for entry in src_uri.split():
1131 if entry.startswith('file://') and entry.endswith('.patch'):
1132 patches.append(entry[7:].split(';')[0])
1133 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
1134 self._check_repo_status(os.path.dirname(recipefile), [])
1135 # First, modify a recipe
1136 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1137 self.track_for_cleanup(tempdir)
1138 self.track_for_cleanup(self.workspacedir)
1139 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1140 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1141 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1142 # Check git repo
1143 self._check_src_repo(tempdir)
1144 # Add a couple of commits
1145 # FIXME: this only tests adding, need to also test update and remove
1146 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
1147 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
1148 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1149 result = runCmd('git add devtool-new-file', cwd=tempdir)
1150 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1151 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1152 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
1153 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
1154 [(' D', '.*/%s$' % patch) for patch in patches]
1155 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1156
1157 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +00001158 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001159 srcurilines = src_uri.split()
1160 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
1161 srcurilines.append('"')
1162 removelines = ['SRCREV = ".*"'] + srcurilines
Andrew Geissler615f2f12022-07-15 14:00:58 -05001163 self._check_diff(result.output, addlines, removelines)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001164 # Now try with auto mode
1165 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
1166 result = runCmd('devtool update-recipe %s' % testrecipe)
1167 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
1168 topleveldir = result.output.strip()
1169 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
1170 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
1171 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
1172 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
1173 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1174
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001175 def test_devtool_update_recipe_append(self):
1176 # Check preconditions
1177 testrecipe = 'mdadm'
1178 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1179 recipefile = bb_vars['FILE']
1180 src_uri = bb_vars['SRC_URI']
1181 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1182 self._check_repo_status(os.path.dirname(recipefile), [])
1183 # First, modify a recipe
1184 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1185 tempsrcdir = os.path.join(tempdir, 'source')
1186 templayerdir = os.path.join(tempdir, 'layer')
1187 self.track_for_cleanup(tempdir)
1188 self.track_for_cleanup(self.workspacedir)
1189 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1190 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1191 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1192 # Check git repo
1193 self._check_src_repo(tempsrcdir)
1194 # Add a commit
1195 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
1196 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1197 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1198 # Create a temporary layer and add it to bblayers.conf
1199 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
1200 # Create the bbappend
1201 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1202 self.assertNotIn('WARNING:', result.output)
1203 # Check recipe is still clean
1204 self._check_repo_status(os.path.dirname(recipefile), [])
1205 # Check bbappend was created
1206 splitpath = os.path.dirname(recipefile).split(os.sep)
1207 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1208 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1209 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
1210 self.assertExists(patchfile, 'Patch file not created')
1211
1212 # Check bbappend contents
Patrick Williams213cb262021-08-07 19:21:33 -05001213 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001214 '\n',
1215 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
1216 '\n']
1217 with open(bbappendfile, 'r') as f:
1218 self.assertEqual(expectedlines, f.readlines())
1219
1220 # Check we can run it again and bbappend isn't modified
1221 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1222 with open(bbappendfile, 'r') as f:
1223 self.assertEqual(expectedlines, f.readlines())
1224 # Drop new commit and check patch gets deleted
1225 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1226 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1227 self.assertNotExists(patchfile, 'Patch file not deleted')
Patrick Williams213cb262021-08-07 19:21:33 -05001228 expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001229 '\n']
1230 with open(bbappendfile, 'r') as f:
1231 self.assertEqual(expectedlines2, f.readlines())
1232 # Put commit back and check we can run it if layer isn't in bblayers.conf
1233 os.remove(bbappendfile)
1234 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1235 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1236 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1237 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1238 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
1239 with open(bbappendfile, 'r') as f:
1240 self.assertEqual(expectedlines, f.readlines())
1241 # Deleting isn't expected to work under these circumstances
1242
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001243 def test_devtool_update_recipe_append_git(self):
1244 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001245 testrecipe = 'mtd-utils-selftest'
Andrew Geissler517393d2023-01-13 08:55:19 -06001246 bb_vars = get_bb_vars(['FILE', 'SRC_URI', 'LAYERSERIES_CORENAMES'], testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001247 recipefile = bb_vars['FILE']
1248 src_uri = bb_vars['SRC_URI']
Andrew Geissler517393d2023-01-13 08:55:19 -06001249 corenames = bb_vars['LAYERSERIES_CORENAMES']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001250 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1251 for entry in src_uri.split():
1252 if entry.startswith('git://'):
1253 git_uri = entry
1254 break
1255 self._check_repo_status(os.path.dirname(recipefile), [])
1256 # First, modify a recipe
1257 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1258 tempsrcdir = os.path.join(tempdir, 'source')
1259 templayerdir = os.path.join(tempdir, 'layer')
1260 self.track_for_cleanup(tempdir)
1261 self.track_for_cleanup(self.workspacedir)
1262 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1263 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1264 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1265 # Check git repo
1266 self._check_src_repo(tempsrcdir)
1267 # Add a commit
1268 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
1269 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1270 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1271 # Create a temporary layer
1272 os.makedirs(os.path.join(templayerdir, 'conf'))
1273 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
1274 f.write('BBPATH .= ":${LAYERDIR}"\n')
1275 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
1276 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
1277 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
1278 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
1279 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Andrew Geissler517393d2023-01-13 08:55:19 -06001280 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "%s"\n' % corenames)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001281 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
1282 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
1283 # Create the bbappend
1284 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1285 self.assertNotIn('WARNING:', result.output)
1286 # Check recipe is still clean
1287 self._check_repo_status(os.path.dirname(recipefile), [])
1288 # Check bbappend was created
1289 splitpath = os.path.dirname(recipefile).split(os.sep)
1290 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1291 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1292 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1293
1294 # Check bbappend contents
1295 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1296 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1297 '\n',
1298 'SRC_URI = "%s"\n' % git_uri,
1299 '\n'])
1300 with open(bbappendfile, 'r') as f:
1301 self.assertEqual(expectedlines, set(f.readlines()))
1302
1303 # Check we can run it again and bbappend isn't modified
1304 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1305 with open(bbappendfile, 'r') as f:
1306 self.assertEqual(expectedlines, set(f.readlines()))
1307 # Drop new commit and check SRCREV changes
1308 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1309 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1310 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1311 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1312 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1313 '\n',
1314 'SRC_URI = "%s"\n' % git_uri,
1315 '\n'])
1316 with open(bbappendfile, 'r') as f:
1317 self.assertEqual(expectedlines, set(f.readlines()))
1318 # Put commit back and check we can run it if layer isn't in bblayers.conf
1319 os.remove(bbappendfile)
1320 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1321 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1322 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1323 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1324 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1325 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1326 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1327 '\n',
1328 'SRC_URI = "%s"\n' % git_uri,
1329 '\n'])
1330 with open(bbappendfile, 'r') as f:
1331 self.assertEqual(expectedlines, set(f.readlines()))
1332 # Deleting isn't expected to work under these circumstances
1333
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001334 def test_devtool_update_recipe_local_files(self):
1335 """Check that local source files are copied over instead of patched"""
1336 testrecipe = 'makedevs'
1337 recipefile = get_bb_var('FILE', testrecipe)
1338 # Setup srctree for modifying the recipe
1339 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1340 self.track_for_cleanup(tempdir)
1341 self.track_for_cleanup(self.workspacedir)
1342 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1343 # (don't bother with cleaning the recipe on teardown, we won't be
1344 # building it)
1345 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1346 # Check git repo
1347 self._check_src_repo(tempdir)
1348 # Try building just to ensure we haven't broken that
1349 bitbake("%s" % testrecipe)
1350 # Edit / commit local source
1351 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1352 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1353 runCmd('echo "Bar" > new-file', cwd=tempdir)
1354 runCmd('git add new-file', cwd=tempdir)
1355 runCmd('git commit -m "Add new file"', cwd=tempdir)
1356 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1357 os.path.dirname(recipefile))
1358 runCmd('devtool update-recipe %s' % testrecipe)
1359 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1360 (' M', '.*/makedevs/makedevs.c$'),
1361 ('??', '.*/makedevs/new-local$'),
1362 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1363 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1364
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001365 def test_devtool_update_recipe_local_files_2(self):
1366 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001367 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001368 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001369 recipedir = os.path.dirname(recipefile)
1370 result = runCmd('git status --porcelain .', cwd=recipedir)
1371 if result.output.strip():
1372 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001373 # Setup srctree for modifying the recipe
1374 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1375 self.track_for_cleanup(tempdir)
1376 self.track_for_cleanup(self.workspacedir)
1377 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1378 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1379 # Check git repo
1380 self._check_src_repo(tempdir)
1381 # Add oe-local-files to Git
1382 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1383 runCmd('git add oe-local-files', cwd=tempdir)
1384 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1385 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001386 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001387 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001388 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001389 runCmd('git commit -m"Remove file"', cwd=tempdir)
1390 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1391 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1392 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1393 runCmd('echo "Gar" > new-file', cwd=tempdir)
1394 runCmd('git add new-file', cwd=tempdir)
1395 runCmd('git commit -m "Add new file"', cwd=tempdir)
1396 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1397 os.path.dirname(recipefile))
1398 # Checkout unmodified file to working copy -> devtool should still pick
1399 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001400 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001401 runCmd('devtool update-recipe %s' % testrecipe)
1402 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001403 (' M', '.*/file1$'),
1404 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001405 ('??', '.*/new-local$'),
1406 ('??', '.*/0001-Add-new-file.patch$')]
1407 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1408
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001409 def test_devtool_update_recipe_with_gitignore(self):
1410 # First, modify the recipe
1411 testrecipe = 'devtool-test-ignored'
1412 bb_vars = get_bb_vars(['FILE'], testrecipe)
1413 recipefile = bb_vars['FILE']
1414 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1415 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
1416 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1417 self.track_for_cleanup(tempdir)
1418 self.track_for_cleanup(self.workspacedir)
1419 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1420 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1421 result = runCmd('devtool modify %s' % testrecipe)
1422 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1423 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1424 # Check recipe got changed as expected
1425 with open(newpatchfile, 'r') as f:
1426 desiredlines = f.readlines()
1427 with open(patchfile, 'r') as f:
1428 newlines = f.readlines()
1429 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1430 # which changes the metadata subject which is added into the patch, but keep
1431 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1432 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1433 self.assertEqual(desiredlines[5:], newlines[5:])
1434
1435 def test_devtool_update_recipe_long_filename(self):
1436 # First, modify the recipe
1437 testrecipe = 'devtool-test-long-filename'
1438 bb_vars = get_bb_vars(['FILE'], testrecipe)
1439 recipefile = bb_vars['FILE']
1440 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1441 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1442 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1443 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1444 self.track_for_cleanup(tempdir)
1445 self.track_for_cleanup(self.workspacedir)
1446 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1447 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1448 result = runCmd('devtool modify %s' % testrecipe)
1449 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1450 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1451 # Check recipe got changed as expected
1452 with open(newpatchfile, 'r') as f:
1453 desiredlines = f.readlines()
1454 with open(patchfile, 'r') as f:
1455 newlines = f.readlines()
1456 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1457 # which changes the metadata subject which is added into the patch, but keep
1458 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1459 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1460 self.assertEqual(desiredlines[5:], newlines[5:])
1461
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001462 def test_devtool_update_recipe_local_files_3(self):
1463 # First, modify the recipe
1464 testrecipe = 'devtool-test-localonly'
1465 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1466 recipefile = bb_vars['FILE']
1467 src_uri = bb_vars['SRC_URI']
1468 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1469 self.track_for_cleanup(tempdir)
1470 self.track_for_cleanup(self.workspacedir)
1471 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1472 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1473 result = runCmd('devtool modify %s' % testrecipe)
1474 # Modify one file
1475 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1476 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1477 result = runCmd('devtool update-recipe %s' % testrecipe)
1478 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1479 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1480
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001481 def test_devtool_update_recipe_local_patch_gz(self):
1482 # First, modify the recipe
1483 testrecipe = 'devtool-test-patch-gz'
1484 if get_bb_var('DISTRO') == 'poky-tiny':
1485 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1486 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1487 recipefile = bb_vars['FILE']
1488 src_uri = bb_vars['SRC_URI']
1489 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1490 self.track_for_cleanup(tempdir)
1491 self.track_for_cleanup(self.workspacedir)
1492 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1493 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1494 result = runCmd('devtool modify %s' % testrecipe)
1495 # Modify one file
1496 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1497 runCmd('echo "Another line" >> README', cwd=srctree)
1498 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1499 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1500 result = runCmd('devtool update-recipe %s' % testrecipe)
1501 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1502 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1503 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1504 result = runCmd('file %s' % patch_gz)
1505 if 'gzip compressed data' not in result.output:
1506 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1507
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001508 def test_devtool_update_recipe_local_files_subdir(self):
1509 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1510 # SRC_URI such that it overwrites a file that was in an archive that
1511 # was also in SRC_URI
1512 # First, modify the recipe
1513 testrecipe = 'devtool-test-subdir'
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 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1524 self.assertExists(testfile, 'Extracted source could not be found')
1525 with open(testfile, 'r') as f:
1526 contents = f.read().rstrip()
1527 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1528 # Test devtool update-recipe without modifying any files
1529 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1530 result = runCmd('devtool update-recipe %s' % testrecipe)
1531 expected_status = []
1532 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1533
Andrew Geissler615f2f12022-07-15 14:00:58 -05001534 def test_devtool_finish_modify_git_subdir(self):
1535 # Check preconditions
1536 testrecipe = 'dos2unix'
Patrick Williams520786c2023-06-25 16:20:36 -05001537 self.append_config('ERROR_QA:remove:pn-dos2unix = "patch-status"\n')
Andrew Geissler615f2f12022-07-15 14:00:58 -05001538 bb_vars = get_bb_vars(['SRC_URI', 'S', 'WORKDIR', 'FILE'], testrecipe)
1539 self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe)
1540 workdir_git = '%s/git/' % bb_vars['WORKDIR']
1541 if not bb_vars['S'].startswith(workdir_git):
1542 self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe)
1543 subdir = bb_vars['S'].split(workdir_git, 1)[1]
1544 # Clean up anything in the workdir/sysroot/sstate cache
1545 bitbake('%s -c cleansstate' % testrecipe)
1546 # Try modifying a recipe
1547 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1548 self.track_for_cleanup(tempdir)
1549 self.track_for_cleanup(self.workspacedir)
1550 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1551 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1552 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1553 testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c')
1554 self.assertExists(testsrcfile, 'Extracted source could not be found')
1555 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
1556 self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo')
1557 # Check git repo
1558 self._check_src_repo(tempdir)
1559 # Modify file
1560 runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile)
1561 result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir)
1562 # Now try updating original recipe
1563 recipefile = bb_vars['FILE']
1564 recipedir = os.path.dirname(recipefile)
1565 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1566 result = runCmd('devtool update-recipe %s' % testrecipe)
1567 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1568 ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))]
1569 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1570 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
1571 removelines = ['SRC_URI = "git://.*"']
1572 addlines = [
1573 'SRC_URI = "git://.* \\\\',
1574 'file://0001-Add-a-comment.patch;patchdir=.. \\\\',
1575 '"'
1576 ]
1577 self._check_diff(result.output, addlines, removelines)
1578 # Put things back so we can run devtool finish on a different layer
1579 runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1580 # Run devtool finish
1581 res = re.search('recipes-.*', recipedir)
1582 self.assertTrue(res, 'Unable to find recipe subdirectory')
1583 recipesubdir = res[0]
1584 self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir))
1585 result = runCmd('devtool finish %s meta-selftest' % testrecipe)
1586 # Check bbappend file contents
1587 appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe)
1588 with open(appendfn, 'r') as f:
1589 appendlines = f.readlines()
1590 expected_appendlines = [
1591 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
1592 '\n',
1593 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n',
1594 '\n'
1595 ]
1596 self.assertEqual(appendlines, expected_appendlines)
1597 self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch'))
1598 # Try building
1599 bitbake('%s -c patch' % testrecipe)
1600
1601
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001602class DevtoolExtractTests(DevtoolBase):
1603
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001604 def test_devtool_extract(self):
1605 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1606 # Try devtool extract
1607 self.track_for_cleanup(tempdir)
1608 self.track_for_cleanup(self.workspacedir)
1609 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1610 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1611 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1612 self._check_src_repo(tempdir)
1613
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001614 def test_devtool_extract_virtual(self):
1615 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1616 # Try devtool extract
1617 self.track_for_cleanup(tempdir)
1618 self.track_for_cleanup(self.workspacedir)
1619 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1620 result = runCmd('devtool extract virtual/make %s' % tempdir)
1621 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1622 self._check_src_repo(tempdir)
1623
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001624 def test_devtool_reset_all(self):
1625 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1626 self.track_for_cleanup(tempdir)
1627 self.track_for_cleanup(self.workspacedir)
1628 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1629 testrecipe1 = 'mdadm'
1630 testrecipe2 = 'cronie'
1631 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1632 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1633 result = runCmd('devtool build %s' % testrecipe1)
1634 result = runCmd('devtool build %s' % testrecipe2)
1635 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1636 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1637 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1638 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1639 result = runCmd('devtool reset -a')
1640 self.assertIn(testrecipe1, result.output)
1641 self.assertIn(testrecipe2, result.output)
1642 result = runCmd('devtool status')
1643 self.assertNotIn(testrecipe1, result.output)
1644 self.assertNotIn(testrecipe2, result.output)
1645 matches1 = glob.glob(stampprefix1 + '*')
1646 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1647 matches2 = glob.glob(stampprefix2 + '*')
1648 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1649
Patrick Williams45852732022-04-02 08:58:32 -05001650 @OETestTag("runqemu")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001651 def test_devtool_deploy_target(self):
Andrew Geissler220dafd2023-10-04 10:18:08 -05001652 self._check_runqemu_prerequisites()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001653 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1654 # Definitions
1655 testrecipe = 'mdadm'
1656 testfile = '/sbin/mdadm'
1657 testimage = 'oe-selftest-image'
1658 testcommand = '/sbin/mdadm --help'
1659 # Build an image to run
1660 bitbake("%s qemu-native qemu-helper-native" % testimage)
1661 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1662 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1663 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1664 # Clean recipe so the first deploy will fail
1665 bitbake("%s -c clean" % testrecipe)
1666 # Try devtool modify
1667 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1668 self.track_for_cleanup(tempdir)
1669 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001670 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001671 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001672 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1673 # Test that deploy-target at this point fails (properly)
1674 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1675 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1676 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1677 result = runCmd('devtool build %s' % testrecipe)
1678 # First try a dry-run of deploy-target
1679 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1680 self.assertIn(' %s' % testfile, result.output)
1681 # Boot the image
1682 with runqemu(testimage) as qemu:
1683 # Now really test deploy-target
1684 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1685 # Run a test command to see if it was installed properly
1686 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1687 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1688 # Check if it deployed all of the files with the right ownership/perms
1689 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1690 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1691 installdir = bb_vars['D']
1692 fakerootenv = bb_vars['FAKEROOTENV']
1693 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001694 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001695 filelist1 = self._process_ls_output(result.output)
1696
1697 # Now look on the target
1698 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1699 self.track_for_cleanup(tempdir2)
1700 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1701 with open(tmpfilelist, 'w') as f:
1702 for line in filelist1:
1703 splitline = line.split()
1704 f.write(splitline[-1] + '\n')
1705 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1706 filelist2 = self._process_ls_output(result.output)
1707 filelist1.sort(key=lambda item: item.split()[-1])
1708 filelist2.sort(key=lambda item: item.split()[-1])
1709 self.assertEqual(filelist1, filelist2)
1710 # Test undeploy-target
1711 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1712 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1713 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1714
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001715 def test_devtool_build_image(self):
1716 """Test devtool build-image plugin"""
1717 # Check preconditions
1718 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1719 image = 'core-image-minimal'
1720 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001721 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001722 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001723 bitbake('%s -c clean' % image)
1724 # Add target and native recipes to workspace
1725 recipes = ['mdadm', 'parted-native']
1726 for recipe in recipes:
1727 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1728 self.track_for_cleanup(tempdir)
1729 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1730 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1731 # Try to build image
1732 result = runCmd('devtool build-image %s' % image)
1733 self.assertNotEqual(result, 0, 'devtool build-image failed')
1734 # Check if image contains expected packages
1735 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1736 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1737 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1738 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1739 for line in f:
1740 splitval = line.split()
1741 if splitval:
1742 pkg = splitval[0]
1743 if pkg in reqpkgs:
1744 reqpkgs.remove(pkg)
1745 if reqpkgs:
1746 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1747
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001748class DevtoolUpgradeTests(DevtoolBase):
1749
Patrick Williams45852732022-04-02 08:58:32 -05001750 def setUp(self):
1751 super().setUp()
1752 try:
1753 runCmd("git config --global user.name")
1754 runCmd("git config --global user.email")
1755 except:
1756 self.skip("Git user.name and user.email must be set")
1757
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001758 def test_devtool_upgrade(self):
1759 # Check preconditions
1760 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1761 self.track_for_cleanup(self.workspacedir)
1762 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1763 # Check parameters
1764 result = runCmd('devtool upgrade -h')
1765 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1766 self.assertIn(param, result.output)
1767 # For the moment, we are using a real recipe.
1768 recipe = 'devtool-upgrade-test1'
1769 version = '1.6.0'
1770 oldrecipefile = get_bb_var('FILE', recipe)
1771 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1772 self.track_for_cleanup(tempdir)
1773 # Check that recipe is not already under devtool control
1774 result = runCmd('devtool status')
1775 self.assertNotIn(recipe, result.output)
1776 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1777 # we are downgrading instead of upgrading.
1778 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1779 # Check if srctree at least is populated
1780 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1781 # Check new recipe subdirectory is present
1782 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1783 # Check new recipe file is present
1784 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1785 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1786 # Check devtool status and make sure recipe is present
1787 result = runCmd('devtool status')
1788 self.assertIn(recipe, result.output)
1789 self.assertIn(tempdir, result.output)
1790 # Check recipe got changed as expected
1791 with open(oldrecipefile + '.upgraded', 'r') as f:
1792 desiredlines = f.readlines()
1793 with open(newrecipefile, 'r') as f:
1794 newlines = f.readlines()
1795 self.assertEqual(desiredlines, newlines)
1796 # Check devtool reset recipe
1797 result = runCmd('devtool reset %s -n' % recipe)
1798 result = runCmd('devtool status')
1799 self.assertNotIn(recipe, result.output)
1800 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1801
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001802 def test_devtool_upgrade_git(self):
1803 # Check preconditions
1804 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1805 self.track_for_cleanup(self.workspacedir)
1806 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1807 recipe = 'devtool-upgrade-test2'
1808 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1809 oldrecipefile = get_bb_var('FILE', recipe)
1810 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1811 self.track_for_cleanup(tempdir)
1812 # Check that recipe is not already under devtool control
1813 result = runCmd('devtool status')
1814 self.assertNotIn(recipe, result.output)
1815 # Check upgrade
1816 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1817 # Check if srctree at least is populated
1818 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1819 # Check new recipe file is present
1820 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1821 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1822 # Check devtool status and make sure recipe is present
1823 result = runCmd('devtool status')
1824 self.assertIn(recipe, result.output)
1825 self.assertIn(tempdir, result.output)
1826 # Check recipe got changed as expected
1827 with open(oldrecipefile + '.upgraded', 'r') as f:
1828 desiredlines = f.readlines()
1829 with open(newrecipefile, 'r') as f:
1830 newlines = f.readlines()
1831 self.assertEqual(desiredlines, newlines)
1832 # Check devtool reset recipe
1833 result = runCmd('devtool reset %s -n' % recipe)
1834 result = runCmd('devtool status')
1835 self.assertNotIn(recipe, result.output)
1836 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1837
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001838 def test_devtool_layer_plugins(self):
1839 """Test that devtool can use plugins from other layers.
1840
1841 This test executes the selftest-reverse command from meta-selftest."""
1842
1843 self.track_for_cleanup(self.workspacedir)
1844 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1845
1846 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1847 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1848 self.assertEqual(result.output, s[::-1])
1849
1850 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1851 dstdir = basedstdir
1852 self.assertExists(dstdir)
1853 for p in paths:
1854 dstdir = os.path.join(dstdir, p)
1855 if not os.path.exists(dstdir):
1856 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001857 if p == "lib":
1858 # Can race with other tests
1859 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1860 else:
1861 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001862 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1863 if srcfile != dstfile:
1864 shutil.copy(srcfile, dstfile)
1865 self.track_for_cleanup(dstfile)
1866
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001867 def test_devtool_load_plugin(self):
1868 """Test that devtool loads only the first found plugin in BBPATH."""
1869
1870 self.track_for_cleanup(self.workspacedir)
1871 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1872
1873 devtool = runCmd("which devtool")
1874 fromname = runCmd("devtool --quiet pluginfile")
1875 srcfile = fromname.output
1876 bbpath = get_bb_var('BBPATH')
1877 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1878 plugincontent = []
1879 with open(srcfile) as fh:
1880 plugincontent = fh.readlines()
1881 try:
1882 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1883 for path in searchpath:
1884 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1885 result = runCmd("devtool --quiet count")
1886 self.assertEqual(result.output, '1')
1887 result = runCmd("devtool --quiet multiloaded")
1888 self.assertEqual(result.output, "no")
1889 for path in searchpath:
1890 result = runCmd("devtool --quiet bbdir")
1891 self.assertEqual(result.output, path)
1892 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1893 finally:
1894 with open(srcfile, 'w') as fh:
1895 fh.writelines(plugincontent)
1896
1897 def _setup_test_devtool_finish_upgrade(self):
1898 # Check preconditions
1899 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1900 self.track_for_cleanup(self.workspacedir)
1901 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1902 # Use a "real" recipe from meta-selftest
1903 recipe = 'devtool-upgrade-test1'
1904 oldversion = '1.5.3'
1905 newversion = '1.6.0'
1906 oldrecipefile = get_bb_var('FILE', recipe)
1907 recipedir = os.path.dirname(oldrecipefile)
1908 result = runCmd('git status --porcelain .', cwd=recipedir)
1909 if result.output.strip():
1910 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1911 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1912 self.track_for_cleanup(tempdir)
1913 # Check that recipe is not already under devtool control
1914 result = runCmd('devtool status')
1915 self.assertNotIn(recipe, result.output)
1916 # Do the upgrade
1917 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
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 # Make a change to the source
1923 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1924 result = runCmd('git status --porcelain', cwd=tempdir)
1925 self.assertIn('M src/pv/number.c', result.output)
1926 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1927 # Check if patch is there
1928 recipedir = os.path.dirname(oldrecipefile)
1929 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1930 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001931 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001932 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001933 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1934 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001935
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001936 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001937 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001938 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1939 self.assertIn('/meta-selftest/', recipedir)
1940 # Try finish to the original layer
1941 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1942 result = runCmd('devtool finish %s meta-selftest' % recipe)
1943 result = runCmd('devtool status')
1944 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1945 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1946 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1947 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001948 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 -05001949 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1950 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1951 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1952 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 -05001953 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 -05001954 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 -05001955 with open(newrecipefile, 'r') as f:
1956 newcontent = f.read()
1957 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1958 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1959 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1960 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1961
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001962
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001963 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001964 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001965 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1966 self.assertIn('/meta-selftest/', recipedir)
1967 # Try finish to a different layer - should create a bbappend
1968 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1969 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1970 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1971 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1972 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1973 self.track_for_cleanup(newrecipedir)
1974 result = runCmd('devtool finish %s oe-core' % recipe)
1975 result = runCmd('devtool status')
1976 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1977 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1978 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1979 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001980 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001981 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1982 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1983 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 -05001984 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 -05001985 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 -05001986 with open(newrecipefile, 'r') as f:
1987 newcontent = f.read()
1988 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1989 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1990 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1991 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 -05001992
1993 def _setup_test_devtool_finish_modify(self):
1994 # Check preconditions
1995 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1996 # Try modifying a recipe
1997 self.track_for_cleanup(self.workspacedir)
1998 recipe = 'mdadm'
1999 oldrecipefile = get_bb_var('FILE', recipe)
2000 recipedir = os.path.dirname(oldrecipefile)
2001 result = runCmd('git status --porcelain .', cwd=recipedir)
2002 if result.output.strip():
2003 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
2004 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2005 self.track_for_cleanup(tempdir)
2006 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
2007 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
2008 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2009 # Test devtool status
2010 result = runCmd('devtool status')
2011 self.assertIn(recipe, result.output)
2012 self.assertIn(tempdir, result.output)
2013 # Make a change to the source
2014 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
2015 result = runCmd('git status --porcelain', cwd=tempdir)
2016 self.assertIn('M maps.c', result.output)
2017 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
2018 for entry in os.listdir(recipedir):
2019 filesdir = os.path.join(recipedir, entry)
2020 if os.path.isdir(filesdir):
2021 break
2022 else:
2023 self.fail('Unable to find recipe files directory for %s' % recipe)
2024 return recipe, oldrecipefile, recipedir, filesdir
2025
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002026 def test_devtool_finish_modify_origlayer(self):
2027 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
2028 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
2029 self.assertIn('/meta/', recipedir)
2030 # Try finish to the original layer
2031 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2032 result = runCmd('devtool finish %s meta' % recipe)
2033 result = runCmd('devtool status')
2034 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2035 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2036 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
2037 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
2038 self._check_repo_status(recipedir, expected_status)
2039
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002040 def test_devtool_finish_modify_otherlayer(self):
2041 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
2042 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
2043 self.assertIn('/meta/', recipedir)
2044 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
2045 appenddir = os.path.join(get_test_layer(), relpth)
2046 self.track_for_cleanup(appenddir)
2047 # Try finish to the original layer
2048 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2049 result = runCmd('devtool finish %s meta-selftest' % recipe)
2050 result = runCmd('devtool status')
2051 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2052 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2053 result = runCmd('git status --porcelain .', cwd=recipedir)
2054 if result.output.strip():
2055 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
2056 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
2057 recipefn = recipefn.split('_')[0] + '_%'
2058 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
2059 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
2060 newdir = os.path.join(appenddir, recipe)
2061 files = os.listdir(newdir)
2062 foundpatch = None
2063 for fn in files:
2064 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
2065 foundpatch = fn
2066 if not foundpatch:
2067 self.fail('No patch file created next to bbappend')
2068 files.remove(foundpatch)
2069 if files:
2070 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
2071
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002072 def test_devtool_rename(self):
2073 # Check preconditions
2074 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
2075 self.track_for_cleanup(self.workspacedir)
2076 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
2077
2078 # First run devtool add
2079 # We already have this recipe in OE-Core, but that doesn't matter
2080 recipename = 'i2c-tools'
2081 recipever = '3.1.2'
2082 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
2083 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
2084 def add_recipe():
2085 result = runCmd('devtool add %s' % url)
2086 self.assertExists(recipefile, 'Expected recipe file not created')
2087 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
2088 checkvars = {}
2089 checkvars['S'] = None
2090 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2091 self._test_recipe_contents(recipefile, checkvars, [])
2092 add_recipe()
2093 # Now rename it - change both name and version
2094 newrecipename = 'mynewrecipe'
2095 newrecipever = '456'
2096 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
2097 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
2098 self.assertExists(newrecipefile, 'Recipe file not renamed')
2099 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2100 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
2101 self.assertExists(newsrctree, 'Source directory not renamed')
2102 checkvars = {}
2103 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
2104 checkvars['SRC_URI'] = url
2105 self._test_recipe_contents(newrecipefile, checkvars, [])
2106 # Try again - change just name this time
2107 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002108 add_recipe()
2109 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
2110 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
2111 self.assertExists(newrecipefile, 'Recipe file not renamed')
2112 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2113 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
2114 checkvars = {}
2115 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
2116 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2117 self._test_recipe_contents(newrecipefile, checkvars, [])
2118 # Try again - change just version this time
2119 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002120 add_recipe()
2121 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
2122 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
2123 self.assertExists(newrecipefile, 'Recipe file not renamed')
2124 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
2125 checkvars = {}
2126 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
2127 checkvars['SRC_URI'] = url
2128 self._test_recipe_contents(newrecipefile, checkvars, [])
2129
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002130 def test_devtool_virtual_kernel_modify(self):
2131 """
2132 Summary: The purpose of this test case is to verify that
2133 devtool modify works correctly when building
2134 the kernel.
2135 Dependencies: NA
2136 Steps: 1. Build kernel with bitbake.
2137 2. Save the config file generated.
2138 3. Clean the environment.
2139 4. Use `devtool modify virtual/kernel` to validate following:
2140 4.1 The source is checked out correctly.
2141 4.2 The resulting configuration is the same as
2142 what was get on step 2.
2143 4.3 The Kernel can be build correctly.
2144 4.4 Changes made on the source are reflected on the
2145 subsequent builds.
2146 4.5 Changes on the configuration are reflected on the
2147 subsequent builds
2148 Expected: devtool modify is able to checkout the source of the kernel
2149 and modification to the source and configurations are reflected
2150 when building the kernel.
Patrick Williams45852732022-04-02 08:58:32 -05002151 """
2152 kernel_provider = self.td['PREFERRED_PROVIDER_virtual/kernel']
2153
Andrew Geissler82c905d2020-04-13 13:39:40 -05002154 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002155 bitbake('%s -c clean' % kernel_provider)
2156 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2157 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
2158 self.track_for_cleanup(tempdir)
2159 self.track_for_cleanup(tempdir_cfg)
2160 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002161 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04002162 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002163 #Step 1
2164 #Here is just generated the config file instead of all the kernel to optimize the
2165 #time of executing this test case.
2166 bitbake('%s -c configure' % kernel_provider)
2167 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
2168 #Step 2
2169 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
2170 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
2171
2172 tmpconfig = os.path.join(tempdir_cfg, '.config')
2173 #Step 3
2174 bitbake('%s -c clean' % kernel_provider)
2175 #Step 4.1
2176 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
2177 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2178 #Step 4.2
2179 configfile = os.path.join(tempdir,'.config')
Patrick Williams45852732022-04-02 08:58:32 -05002180 runCmd('diff %s %s' % (tmpconfig, configfile))
2181
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002182 #Step 4.3
2183 #NOTE: virtual/kernel is mapped to kernel_provider
Patrick Williams45852732022-04-02 08:58:32 -05002184 runCmd('devtool build %s' % kernel_provider)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002185 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
2186 self.assertExists(kernelfile, 'Kernel was not build correctly')
2187
2188 #Modify the kernel source
Patrick Williams45852732022-04-02 08:58:32 -05002189 modfile = os.path.join(tempdir, 'init/version.c')
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002190 # Moved to uts.h in 6.1 onwards
2191 modfile2 = os.path.join(tempdir, 'include/linux/uts.h')
2192 runCmd("sed -i 's/Linux/LiNuX/g' %s %s" % (modfile, modfile2))
Patrick Williams45852732022-04-02 08:58:32 -05002193
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002194 #Modify the configuration
Patrick Williams45852732022-04-02 08:58:32 -05002195 codeconfigfile = os.path.join(tempdir, '.config.new')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002196 modconfopt = "CONFIG_SG_POOL=n"
Patrick Williams45852732022-04-02 08:58:32 -05002197 runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
2198
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002199 #Build again kernel with devtool
Patrick Williams45852732022-04-02 08:58:32 -05002200 runCmd('devtool build %s' % kernel_provider)
2201
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002202 #Step 4.4
Patrick Williams45852732022-04-02 08:58:32 -05002203 runCmd("grep '%s' %s" % ('LiNuX', kernelfile))
2204
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002205 #Step 4.5
Patrick Williams45852732022-04-02 08:58:32 -05002206 runCmd("grep %s %s" % (modconfopt, codeconfigfile))