blob: b577f6d62a11ce61c202c59a3775a1b103519501 [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 = []
30
31 # We need to take a copy of the meta layer so we can modify it and not
32 # have any races against other tests that might be running in parallel
33 # however things like COREBASE mean that you can't just copy meta, you
34 # need the whole repository.
35 def bblayers_edit_cb(layerpath, canonical_layerpath):
36 global oldmetapath
37 if not canonical_layerpath.endswith('/'):
38 # This helps us match exactly when we're using this path later
39 canonical_layerpath += '/'
40 if not edited_layers and canonical_layerpath.endswith('/meta/'):
41 canonical_layerpath = os.path.realpath(canonical_layerpath) + '/'
42 edited_layers.append(layerpath)
43 oldmetapath = os.path.realpath(layerpath)
Patrick Williamse760df82023-05-26 11:10:49 -050044
45 # when downloading poky from tar.gz some tests will be skipped (BUG 12389)
46 try:
47 runCmd('git rev-parse --is-inside-work-tree', cwd=canonical_layerpath)
48 except:
49 raise unittest.SkipTest("devtool tests require folder to be a git repo")
50
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080051 result = runCmd('git rev-parse --show-toplevel', cwd=canonical_layerpath)
52 oldreporoot = result.output.rstrip()
53 newmetapath = os.path.join(corecopydir, os.path.relpath(oldmetapath, oldreporoot))
54 runCmd('git clone %s %s' % (oldreporoot, corecopydir), cwd=templayerdir)
55 # Now we need to copy any modified files
56 # You might ask "why not just copy the entire tree instead of
57 # cloning and doing this?" - well, the problem with that is
58 # TMPDIR or an equally large subdirectory might exist
59 # under COREBASE and we don't want to copy that, so we have
60 # to be selective.
61 result = runCmd('git status --porcelain', cwd=oldreporoot)
62 for line in result.output.splitlines():
63 if line.startswith(' M ') or line.startswith('?? '):
64 relpth = line.split()[1]
65 pth = os.path.join(oldreporoot, relpth)
66 if pth.startswith(canonical_layerpath):
67 if relpth.endswith('/'):
68 destdir = os.path.join(corecopydir, relpth)
Andrew Geisslerc3d88e42020-10-02 09:45:00 -050069 # avoid race condition by not copying .pyc files YPBZ#13421,13803
Andrew Geisslerd1e89492021-02-12 15:35:20 -060070 shutil.copytree(pth, destdir, ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080071 else:
72 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
73 bb.utils.mkdirhier(destdir)
74 shutil.copy2(pth, destdir)
75 return newmetapath
76 else:
77 return layerpath
78 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
79
80def tearDownModule():
81 if oldmetapath:
82 edited_layers = []
83 def bblayers_edit_cb(layerpath, canonical_layerpath):
84 if not edited_layers and canonical_layerpath.endswith('/meta'):
85 edited_layers.append(layerpath)
86 return oldmetapath
87 else:
88 return layerpath
89 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
90 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
91 shutil.rmtree(templayerdir)
92
Andrew Geissler595f6302022-01-24 19:11:47 +000093class DevtoolTestCase(OESelftestTestCase):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080094
95 def setUp(self):
96 """Test case setup function"""
Andrew Geissler595f6302022-01-24 19:11:47 +000097 super(DevtoolTestCase, self).setUp()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080098 self.workspacedir = os.path.join(self.builddir, 'workspace')
99 self.assertTrue(not os.path.exists(self.workspacedir),
100 'This test cannot be run with a workspace directory '
101 'under the build directory')
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800102
103 def _check_src_repo(self, repo_dir):
104 """Check srctree git repository"""
105 self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')),
106 'git repository for external source tree not found')
107 result = runCmd('git status --porcelain', cwd=repo_dir)
108 self.assertEqual(result.output.strip(), "",
109 'Created git repo is not clean')
110 result = runCmd('git symbolic-ref HEAD', cwd=repo_dir)
111 self.assertEqual(result.output.strip(), "refs/heads/devtool",
112 'Wrong branch in git repo')
113
114 def _check_repo_status(self, repo_dir, expected_status):
115 """Check the worktree status of a repository"""
116 result = runCmd('git status . --porcelain',
117 cwd=repo_dir)
118 for line in result.output.splitlines():
119 for ind, (f_status, fn_re) in enumerate(expected_status):
120 if re.match(fn_re, line[3:]):
121 if f_status != line[:2]:
122 self.fail('Unexpected status in line: %s' % line)
123 expected_status.pop(ind)
124 break
125 else:
126 self.fail('Unexpected modified file in line: %s' % line)
127 if expected_status:
128 self.fail('Missing file changes: %s' % expected_status)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500129
130 def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
131 with open(recipefile, 'r') as f:
132 invar = None
133 invalue = None
Brad Bishop6dbb3162019-11-25 09:41:34 -0500134 inherits = set()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500135 for line in f:
136 var = None
137 if invar:
138 value = line.strip().strip('"')
139 if value.endswith('\\'):
140 invalue += ' ' + value[:-1].strip()
141 continue
142 else:
143 invalue += ' ' + value.strip()
144 var = invar
145 value = invalue
146 invar = None
147 elif '=' in line:
148 splitline = line.split('=', 1)
149 var = splitline[0].rstrip()
150 value = splitline[1].strip().strip('"')
151 if value.endswith('\\'):
152 invalue = value[:-1].strip()
153 invar = var
154 continue
155 elif line.startswith('inherit '):
Brad Bishop6dbb3162019-11-25 09:41:34 -0500156 inherits.update(line.split()[1:])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500157
158 if var and var in checkvars:
159 needvalue = checkvars.pop(var)
160 if needvalue is None:
161 self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value))
162 if isinstance(needvalue, set):
163 if var == 'LICENSE':
164 value = set(value.split(' & '))
165 else:
166 value = set(value.split())
167 self.assertEqual(value, needvalue, 'values for %s do not match' % var)
168
169
170 missingvars = {}
171 for var, value in checkvars.items():
172 if value is not None:
173 missingvars[var] = value
174 self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars)
175
176 for inherit in checkinherits:
177 self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
178
179 def _check_bbappend(self, testrecipe, recipefile, appenddir):
180 result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
181 resultlines = result.output.splitlines()
182 inrecipe = False
183 bbappends = []
184 bbappendfile = None
185 for line in resultlines:
186 if inrecipe:
187 if line.startswith(' '):
188 bbappends.append(line.strip())
189 else:
190 break
191 elif line == '%s:' % os.path.basename(recipefile):
192 inrecipe = True
193 self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
194 for bbappend in bbappends:
195 if bbappend.startswith(appenddir):
196 bbappendfile = bbappend
197 break
198 else:
199 self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
200 return bbappendfile
201
202 def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
203 create_temp_layer(templayerdir, templayername, priority, recipepathspec)
204 if addlayer:
205 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
206 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
207
208 def _process_ls_output(self, output):
209 """
210 Convert ls -l output to a format we can reasonably compare from one context
211 to another (e.g. from host to target)
212 """
213 filelist = []
214 for line in output.splitlines():
215 splitline = line.split()
216 if len(splitline) < 8:
217 self.fail('_process_ls_output: invalid output line: %s' % line)
218 # Remove trailing . on perms
219 splitline[0] = splitline[0].rstrip('.')
220 # Remove leading . on paths
221 splitline[-1] = splitline[-1].lstrip('.')
222 # Drop fields we don't want to compare
223 del splitline[7]
224 del splitline[6]
225 del splitline[5]
226 del splitline[4]
227 del splitline[1]
228 filelist.append(' '.join(splitline))
229 return filelist
230
Andrew Geissler615f2f12022-07-15 14:00:58 -0500231 def _check_diff(self, diffoutput, addlines, removelines):
232 """Check output from 'git diff' matches expectation"""
233 remaining_addlines = addlines[:]
234 remaining_removelines = removelines[:]
235 for line in diffoutput.splitlines():
236 if line.startswith('+++') or line.startswith('---'):
237 continue
238 elif line.startswith('+'):
239 matched = False
240 for item in addlines:
241 if re.match(item, line[1:].strip()):
242 matched = True
243 remaining_addlines.remove(item)
244 break
245 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
246 elif line.startswith('-'):
247 matched = False
248 for item in removelines:
249 if re.match(item, line[1:].strip()):
250 matched = True
251 remaining_removelines.remove(item)
252 break
253 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
254 if remaining_addlines:
255 self.fail('Expected added lines not found: %s' % remaining_addlines)
256 if remaining_removelines:
257 self.fail('Expected removed lines not found: %s' % remaining_removelines)
258
Andrew Geissler220dafd2023-10-04 10:18:08 -0500259 def _check_runqemu_prerequisites(self):
260 """Check runqemu is available
261
262 Whilst some tests would seemingly be better placed as a runtime test,
263 unfortunately the runtime tests run under bitbake and you can't run
264 devtool within bitbake (since devtool needs to run bitbake itself).
265 Additionally we are testing build-time functionality as well, so
266 really this has to be done as an oe-selftest test.
267 """
268 machine = get_bb_var('MACHINE')
269 if not machine.startswith('qemu'):
270 self.skipTest('This test only works with qemu machines')
271 if not os.path.exists('/etc/runqemu-nosudo'):
272 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
273 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
274 if result.status != 0:
275 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
276 if result.status != 0:
277 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
278 for line in result.output.splitlines():
279 if line.startswith('tap'):
280 break
281 else:
282 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
283
Patrick Williams92b42cb2022-09-03 06:53:57 -0500284 def _test_devtool_add_git_url(self, git_url, version, pn, resulting_src_uri):
285 self.track_for_cleanup(self.workspacedir)
286 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
287 result = runCmd('devtool add --version %s %s %s' % (version, pn, git_url))
288 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
289 # Check the recipe name is correct
290 recipefile = get_bb_var('FILE', pn)
291 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
292 self.assertIn(recipefile, result.output)
293 # Test devtool status
294 result = runCmd('devtool status')
295 self.assertIn(pn, result.output)
296 self.assertIn(recipefile, result.output)
297 checkvars = {}
298 checkvars['SRC_URI'] = resulting_src_uri
299 self._test_recipe_contents(recipefile, checkvars, [])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500300
Andrew Geissler595f6302022-01-24 19:11:47 +0000301class DevtoolBase(DevtoolTestCase):
302
303 @classmethod
304 def setUpClass(cls):
305 super(DevtoolBase, cls).setUpClass()
306 bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
307 cls.original_sstate = bb_vars['SSTATE_DIR']
308 cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
309 cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
310 cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
311 % cls.original_sstate)
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500312 cls.sstate_conf += ('BB_HASHSERVE_UPSTREAM = "hashserv.yocto.io:8687"\n')
Andrew Geissler595f6302022-01-24 19:11:47 +0000313
314 @classmethod
315 def tearDownClass(cls):
316 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
317 runCmd('rm -rf %s' % cls.devtool_sstate)
318 super(DevtoolBase, cls).tearDownClass()
319
320 def setUp(self):
321 """Test case setup function"""
322 super(DevtoolBase, self).setUp()
323 self.append_config(self.sstate_conf)
324
325
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500326class DevtoolTests(DevtoolBase):
327
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500328 def test_create_workspace(self):
329 # Check preconditions
330 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400331 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 -0400332 # remove conf/devtool.conf to avoid it corrupting tests
333 devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
334 self.track_for_cleanup(devtoolconf)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500335 # Try creating a workspace layer with a specific path
336 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
337 self.track_for_cleanup(tempdir)
338 result = runCmd('devtool create-workspace %s' % tempdir)
339 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
340 result = runCmd('bitbake-layers show-layers')
341 self.assertIn(tempdir, result.output)
342 # Try creating a workspace layer with the default path
343 self.track_for_cleanup(self.workspacedir)
344 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
345 result = runCmd('devtool create-workspace')
346 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
347 result = runCmd('bitbake-layers show-layers')
348 self.assertNotIn(tempdir, result.output)
349 self.assertIn(self.workspacedir, result.output)
350
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800351class DevtoolAddTests(DevtoolBase):
352
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500353 def test_devtool_add(self):
354 # Fetch source
355 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
356 self.track_for_cleanup(tempdir)
357 pn = 'pv'
358 pv = '1.5.3'
Andrew Geissler09209ee2020-12-13 08:44:15 -0600359 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500360 result = runCmd('wget %s' % url, cwd=tempdir)
361 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
362 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
363 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
364 # Test devtool add
365 self.track_for_cleanup(self.workspacedir)
366 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
367 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
368 result = runCmd('devtool add %s %s' % (pn, srcdir))
369 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
370 # Test devtool status
371 result = runCmd('devtool status')
372 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
373 self.assertIn(recipepath, result.output)
374 self.assertIn(srcdir, result.output)
375 # Test devtool find-recipe
376 result = runCmd('devtool -q find-recipe %s' % pn)
377 self.assertEqual(recipepath, result.output.strip())
378 # Test devtool edit-recipe
379 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
380 self.assertEqual('123 %s' % recipepath, result.output.strip())
381 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
382 bitbake('%s -c cleansstate' % pn)
383 # Test devtool build
384 result = runCmd('devtool build %s' % pn)
385 bb_vars = get_bb_vars(['D', 'bindir'], pn)
386 installdir = bb_vars['D']
387 self.assertTrue(installdir, 'Could not query installdir variable')
388 bindir = bb_vars['bindir']
389 self.assertTrue(bindir, 'Could not query bindir variable')
390 if bindir[0] == '/':
391 bindir = bindir[1:]
392 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
393
Andrew Geissler8f840682023-07-21 09:09:43 -0500394 def test_devtool_add_binary(self):
395 # Create a binary package containing a known test file
396 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
397 self.track_for_cleanup(tempdir)
398 pn = 'tst-bin'
399 pv = '1.0'
400 test_file_dir = "var/lib/%s/" % pn
401 test_file_name = "test_file"
402 test_file_content = "TEST CONTENT"
403 test_file_package_root = os.path.join(tempdir, pn)
404 test_file_dir_full = os.path.join(test_file_package_root, test_file_dir)
405 bb.utils.mkdirhier(test_file_dir_full)
406 with open(os.path.join(test_file_dir_full, test_file_name), "w") as f:
407 f.write(test_file_content)
408 bin_package_path = os.path.join(tempdir, "%s.tar.gz" % pn)
409 runCmd("tar czf %s -C %s ." % (bin_package_path, test_file_package_root))
410
411 # Test devtool add -b on the binary package
412 self.track_for_cleanup(self.workspacedir)
413 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
414 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
415 result = runCmd('devtool add -b %s %s' % (pn, bin_package_path))
416 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
417
418 # Build the resulting recipe
419 result = runCmd('devtool build %s' % pn)
420 installdir = get_bb_var('D', pn)
421 self.assertTrue(installdir, 'Could not query installdir variable')
422
423 # Check that a known file from the binary package has indeed been installed
424 self.assertTrue(os.path.isfile(os.path.join(installdir, test_file_dir, test_file_name)), '%s not found in D' % test_file_name)
425
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500426 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800427 # We need dbus built so that DEPENDS recognition works
428 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500429 # Fetch source from a remote URL, but do it outside of devtool
430 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
431 self.track_for_cleanup(tempdir)
432 pn = 'dbus-wait'
433 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
434 # We choose an https:// git URL here to check rewriting the URL works
435 url = 'https://git.yoctoproject.org/git/dbus-wait'
436 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
437 # instead of the directory name
438 result = runCmd('git clone %s noname' % url, cwd=tempdir)
439 srcdir = os.path.join(tempdir, 'noname')
440 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
441 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
442 # Test devtool add
443 self.track_for_cleanup(self.workspacedir)
444 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
445 # Don't specify a name since we should be able to auto-detect it
446 result = runCmd('devtool add %s' % srcdir)
447 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
448 # Check the recipe name is correct
449 recipefile = get_bb_var('FILE', pn)
450 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
451 self.assertIn(recipefile, result.output)
452 # Test devtool status
453 result = runCmd('devtool status')
454 self.assertIn(pn, result.output)
455 self.assertIn(srcdir, result.output)
456 self.assertIn(recipefile, result.output)
457 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000458 checkvars['LICENSE'] = 'GPL-2.0-only'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500459 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
460 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400461 checkvars['PV'] = '0.1+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000462 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500463 checkvars['SRCREV'] = srcrev
464 checkvars['DEPENDS'] = set(['dbus'])
465 self._test_recipe_contents(recipefile, checkvars, [])
466
Patrick Williams92b42cb2022-09-03 06:53:57 -0500467 def test_devtool_add_git_style1(self):
468 version = 'v3.1.0'
469 pn = 'mbedtls'
470 # this will trigger reformat_git_uri with branch parameter in url
471 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https'"
472 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https"
473 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
474
475 def test_devtool_add_git_style2(self):
476 version = 'v3.1.0'
477 pn = 'mbedtls'
478 # this will trigger reformat_git_uri with branch parameter in url
479 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;protocol=https'"
480 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;protocol=https;branch=master"
481 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
482
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500483 def test_devtool_add_library(self):
484 # Fetch source
485 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
486 self.track_for_cleanup(tempdir)
487 version = '1.1'
488 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
489 result = runCmd('wget %s' % url, cwd=tempdir)
490 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
491 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
492 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
493 # Test devtool add (and use -V so we test that too)
494 self.track_for_cleanup(self.workspacedir)
495 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
496 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
497 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
498 # Test devtool status
499 result = runCmd('devtool status')
500 self.assertIn('libftdi', result.output)
501 self.assertIn(srcdir, result.output)
502 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
503 bitbake('libftdi -c cleansstate')
504 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
505 # There's also the matter of it installing cmake files to a path we don't
506 # normally cover, which triggers the installed-vs-shipped QA test we have
507 # within do_package
508 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
509 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
510 with open(recipefile, 'a') as f:
Patrick Williams213cb262021-08-07 19:21:33 -0500511 f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500512 # We don't have the ability to pick up this dependency automatically yet...
513 f.write('\nDEPENDS += "libusb1"\n')
514 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
515 # Test devtool build
516 result = runCmd('devtool build libftdi')
517 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
518 staging_libdir = bb_vars['TESTLIBOUTPUT']
519 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
520 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)
521 # Test devtool reset
522 stampprefix = bb_vars['STAMP']
523 result = runCmd('devtool reset libftdi')
524 result = runCmd('devtool status')
525 self.assertNotIn('libftdi', result.output)
526 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
527 matches = glob.glob(stampprefix + '*')
528 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
529 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
530
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500531 def test_devtool_add_fetch(self):
532 # Fetch source
533 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
534 self.track_for_cleanup(tempdir)
535 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400536 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500537 testrecipe = 'python-markupsafe'
538 srcdir = os.path.join(tempdir, testrecipe)
539 # Test devtool add
540 self.track_for_cleanup(self.workspacedir)
541 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
542 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
543 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
544 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
545 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
546 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
547 # Test devtool status
548 result = runCmd('devtool status')
549 self.assertIn(testrecipe, result.output)
550 self.assertIn(srcdir, result.output)
551 # Check recipe
552 recipefile = get_bb_var('FILE', testrecipe)
553 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
554 checkvars = {}
555 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
556 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
557 self._test_recipe_contents(recipefile, checkvars, [])
558 # Try with version specified
559 result = runCmd('devtool reset -n %s' % testrecipe)
560 shutil.rmtree(srcdir)
561 fakever = '1.9'
562 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
563 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
564 # Test devtool status
565 result = runCmd('devtool status')
566 self.assertIn(testrecipe, result.output)
567 self.assertIn(srcdir, result.output)
568 # Check recipe
569 recipefile = get_bb_var('FILE', testrecipe)
570 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
571 checkvars = {}
572 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
573 checkvars['SRC_URI'] = url
574 self._test_recipe_contents(recipefile, checkvars, [])
Andrew Geissler615f2f12022-07-15 14:00:58 -0500575
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500576 def test_devtool_add_fetch_git(self):
577 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
578 self.track_for_cleanup(tempdir)
579 url = 'gitsm://git.yoctoproject.org/mraa'
Andrew Geissler595f6302022-01-24 19:11:47 +0000580 url_branch = '%s;branch=master' % url
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500581 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
582 testrecipe = 'mraa'
583 srcdir = os.path.join(tempdir, testrecipe)
584 # Test devtool add
585 self.track_for_cleanup(self.workspacedir)
586 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
587 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
588 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
589 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
590 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
591 # Test devtool status
592 result = runCmd('devtool status')
593 self.assertIn(testrecipe, result.output)
594 self.assertIn(srcdir, result.output)
595 # Check recipe
596 recipefile = get_bb_var('FILE', testrecipe)
597 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
598 checkvars = {}
599 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400600 checkvars['PV'] = '1.0+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000601 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500602 checkvars['SRCREV'] = '${AUTOREV}'
603 self._test_recipe_contents(recipefile, checkvars, [])
604 # Try with revision and version specified
605 result = runCmd('devtool reset -n %s' % testrecipe)
606 shutil.rmtree(srcdir)
607 url_rev = '%s;rev=%s' % (url, checkrev)
608 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
609 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
610 # Test devtool status
611 result = runCmd('devtool status')
612 self.assertIn(testrecipe, result.output)
613 self.assertIn(srcdir, result.output)
614 # Check recipe
615 recipefile = get_bb_var('FILE', testrecipe)
616 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
617 checkvars = {}
618 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400619 checkvars['PV'] = '1.5+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000620 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500621 checkvars['SRCREV'] = checkrev
622 self._test_recipe_contents(recipefile, checkvars, [])
623
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500624 def test_devtool_add_fetch_simple(self):
625 # Fetch source from a remote URL, auto-detecting name
626 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
627 self.track_for_cleanup(tempdir)
628 testver = '1.6.0'
629 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
630 testrecipe = 'pv'
631 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
632 # Test devtool add
633 self.track_for_cleanup(self.workspacedir)
634 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
635 result = runCmd('devtool add %s' % url)
636 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
637 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
638 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
639 # Test devtool status
640 result = runCmd('devtool status')
641 self.assertIn(testrecipe, result.output)
642 self.assertIn(srcdir, result.output)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500643 # Check recipedevtool add
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500644 recipefile = get_bb_var('FILE', testrecipe)
645 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
646 checkvars = {}
647 checkvars['S'] = None
648 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
649 self._test_recipe_contents(recipefile, checkvars, [])
650
Andrew Geissler82c905d2020-04-13 13:39:40 -0500651 def test_devtool_add_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600652 collections = get_bb_var('BBFILE_COLLECTIONS').split()
653 if "openembedded-layer" not in collections:
654 self.skipTest("Test needs meta-oe for nodejs")
655
Andrew Geissler82c905d2020-04-13 13:39:40 -0500656 pn = 'savoirfairelinux-node-server-example'
657 pv = '1.0.0'
658 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
659 # Test devtool add
660 self.track_for_cleanup(self.workspacedir)
661 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
662 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
663 result = runCmd('devtool add \'%s\'' % url)
664 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
665 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
666 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
667 # Test devtool status
668 result = runCmd('devtool status')
669 self.assertIn(pn, result.output)
670 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
671 bitbake('%s -c cleansstate' % pn)
672 # Test devtool build
673 result = runCmd('devtool build %s' % pn)
674
Andrew Geissler615f2f12022-07-15 14:00:58 -0500675 def test_devtool_add_python_egg_requires(self):
676 # Fetch source
677 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
678 self.track_for_cleanup(tempdir)
679 testver = '0.14.0'
680 url = 'https://files.pythonhosted.org/packages/e9/9e/25d59f5043cf763833b2581c8027fa92342c4cf8ee523b498ecdf460c16d/uvicorn-%s.tar.gz' % testver
681 testrecipe = 'python3-uvicorn'
682 srcdir = os.path.join(tempdir, testrecipe)
683 # Test devtool add
684 self.track_for_cleanup(self.workspacedir)
685 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
686 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
687
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800688class DevtoolModifyTests(DevtoolBase):
689
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500690 def test_devtool_modify(self):
691 import oe.path
692
693 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
694 self.track_for_cleanup(tempdir)
695 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500696 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400697 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500698 result = runCmd('devtool modify mdadm -x %s' % tempdir)
699 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
700 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
701 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
702 self.assertTrue(matches, 'bbappend not created %s' % result.output)
703
704 # Test devtool status
705 result = runCmd('devtool status')
706 self.assertIn('mdadm', result.output)
707 self.assertIn(tempdir, result.output)
708 self._check_src_repo(tempdir)
709
710 bitbake('mdadm -C unpack')
711
712 def check_line(checkfile, expected, message, present=True):
713 # Check for $expected, on a line on its own, in checkfile.
714 with open(checkfile, 'r') as f:
715 if present:
716 self.assertIn(expected + '\n', f, message)
717 else:
718 self.assertNotIn(expected + '\n', f, message)
719
720 modfile = os.path.join(tempdir, 'mdadm.8.in')
721 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
722 pkgd = bb_vars['PKGD']
723 self.assertTrue(pkgd, 'Could not query PKGD variable')
724 mandir = bb_vars['mandir']
725 self.assertTrue(mandir, 'Could not query mandir variable')
726 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
727
728 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
729 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
730
731 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
732 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
733
734 bitbake('mdadm -c package')
735 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
736
737 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
738 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
739
740 bitbake('mdadm -c package')
741 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
742
743 result = runCmd('devtool reset mdadm')
744 result = runCmd('devtool status')
745 self.assertNotIn('mdadm', result.output)
746
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500747 def test_devtool_buildclean(self):
748 def assertFile(path, *paths):
749 f = os.path.join(path, *paths)
750 self.assertExists(f)
751 def assertNoFile(path, *paths):
752 f = os.path.join(path, *paths)
753 self.assertNotExists(f)
754
755 # Clean up anything in the workdir/sysroot/sstate cache
756 bitbake('mdadm m4 -c cleansstate')
757 # Try modifying a recipe
758 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
759 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
760 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
761 self.track_for_cleanup(tempdir_mdadm)
762 self.track_for_cleanup(tempdir_m4)
763 self.track_for_cleanup(builddir_m4)
764 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500765 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400766 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500767 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
768 try:
769 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
770 runCmd('devtool modify m4 -x %s' % tempdir_m4)
771 assertNoFile(tempdir_mdadm, 'mdadm')
772 assertNoFile(builddir_m4, 'src/m4')
773 result = bitbake('m4 -e')
774 result = bitbake('mdadm m4 -c compile')
775 self.assertEqual(result.status, 0)
776 assertFile(tempdir_mdadm, 'mdadm')
777 assertFile(builddir_m4, 'src/m4')
778 # Check that buildclean task exists and does call make clean
779 bitbake('mdadm m4 -c buildclean')
780 assertNoFile(tempdir_mdadm, 'mdadm')
781 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400782 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500783 bitbake('mdadm m4 -c compile')
784 assertFile(tempdir_mdadm, 'mdadm')
785 assertFile(builddir_m4, 'src/m4')
786 bitbake('mdadm m4 -c clean')
787 # Check that buildclean task is run before clean for B == S
788 assertNoFile(tempdir_mdadm, 'mdadm')
789 # Check that buildclean task is not run before clean for B != S
790 assertFile(builddir_m4, 'src/m4')
791 finally:
792 self.delete_recipeinc('m4')
793
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500794 def test_devtool_modify_invalid(self):
795 # Try modifying some recipes
796 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
797 self.track_for_cleanup(tempdir)
798 self.track_for_cleanup(self.workspacedir)
799 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
800
Andrew Geissler5199d832021-09-24 16:47:35 -0500801 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500802 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
803 result = runCmd('bitbake-layers show-recipes gcc-source*')
804 for line in result.output.splitlines():
805 # just match those lines that contain a real target
806 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
807 if m:
808 testrecipes.append(m.group('recipe'))
809 for testrecipe in testrecipes:
810 # Check it's a valid recipe
811 bitbake('%s -e' % testrecipe)
812 # devtool extract should fail
813 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
814 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
815 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
816 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
817 # devtool modify should fail
818 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
819 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
820 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
821
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500822 def test_devtool_modify_native(self):
823 # Check preconditions
824 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
825 # Try modifying some recipes
826 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
827 self.track_for_cleanup(tempdir)
828 self.track_for_cleanup(self.workspacedir)
829 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
830
831 bbclassextended = False
832 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500833 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500834 for testrecipe in testrecipes:
835 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
836 if not bbclassextended:
837 bbclassextended = checkextend
838 if not inheritnative:
839 inheritnative = not checkextend
840 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
841 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
842 result = runCmd('devtool build %s' % testrecipe)
843 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
844 result = runCmd('devtool reset %s' % testrecipe)
845 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
846
847 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
848 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 -0500849
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600850 def test_devtool_modify_localfiles_only(self):
851 # Check preconditions
852 testrecipe = 'base-files'
853 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
854 foundlocalonly = False
855 correct_symlink = False
856 for item in src_uri:
857 if item.startswith('file://'):
858 if '.patch' not in item:
859 foundlocalonly = True
860 else:
861 foundlocalonly = False
862 break
863 self.assertTrue(foundlocalonly, 'This test expects the %s recipe to fetch local files only and it seems that it no longer does' % testrecipe)
864 # Clean up anything in the workdir/sysroot/sstate cache
865 bitbake('%s -c cleansstate' % testrecipe)
866 # Try modifying a recipe
867 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
868 self.track_for_cleanup(tempdir)
869 self.track_for_cleanup(self.workspacedir)
870 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
871 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
872 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
873 srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
874 srclink = os.path.join(tempdir, 'share/dot.bashrc')
875 self.assertExists(srcfile, 'Extracted source could not be found')
876 if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
877 correct_symlink = True
878 self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500879
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600880 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
881 self.assertTrue(matches, 'bbappend not created')
882 # Test devtool status
883 result = runCmd('devtool status')
884 self.assertIn(testrecipe, result.output)
885 self.assertIn(tempdir, result.output)
886 # Try building
887 bitbake(testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500888
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500889 def test_devtool_modify_git(self):
890 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400891 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500892 src_uri = get_bb_var('SRC_URI', testrecipe)
893 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
894 # Clean up anything in the workdir/sysroot/sstate cache
895 bitbake('%s -c cleansstate' % testrecipe)
896 # Try modifying a recipe
897 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
898 self.track_for_cleanup(tempdir)
899 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500900 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400901 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500902 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400903 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500904 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 -0400905 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500906 self.assertTrue(matches, 'bbappend not created')
907 # Test devtool status
908 result = runCmd('devtool status')
909 self.assertIn(testrecipe, result.output)
910 self.assertIn(tempdir, result.output)
911 # Check git repo
912 self._check_src_repo(tempdir)
913 # Try building
914 bitbake(testrecipe)
915
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500916 def test_devtool_modify_git_crates_subpath(self):
917 # This tests two things in devtool context:
918 # - that we support local git dependencies for cargo based recipe
919 # - that we support patches in SRC_URI when git url contains subpath parameter
920
921 # Check preconditions:
922 # recipe inherits cargo
923 # git:// uri with a subpath as the main package
924 # some crate:// in SRC_URI
925 # others git:// in SRC_URI
926 # cointains a patch
927 testrecipe = 'zvariant'
928 bb_vars = get_bb_vars(['SRC_URI', 'FILE', 'WORKDIR', 'CARGO_HOME'], testrecipe)
929 recipefile = bb_vars['FILE']
930 workdir = bb_vars['WORKDIR']
931 cargo_home = bb_vars['CARGO_HOME']
932 src_uri = bb_vars['SRC_URI'].split()
933 self.assertTrue(src_uri[0].startswith('git://'),
934 'This test expects the %s recipe to have a git repo has its main uri' % testrecipe)
935 self.assertIn(';subpath=', src_uri[0],
936 'This test expects the %s recipe to have a git uri with subpath' % testrecipe)
937 self.assertTrue(any([uri.startswith('crate://') for uri in src_uri]),
938 'This test expects the %s recipe to have some crates in its src uris' % testrecipe)
939 self.assertGreater(sum(map(lambda x:x.startswith('git://'), src_uri)), 2,
940 'This test expects the %s recipe to have several git:// uris' % testrecipe)
941 self.assertTrue(any([uri.startswith('file://') and '.patch' in uri for uri in src_uri]),
942 'This test expects the %s recipe to have a patch in its src uris' % testrecipe)
943
Andrew Geissler028142b2023-05-05 11:29:21 -0500944 self._test_recipe_contents(recipefile, {}, ['ptest-cargo'])
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500945
946 # Clean up anything in the workdir/sysroot/sstate cache
947 bitbake('%s -c cleansstate' % testrecipe)
948 # Try modifying a recipe
949 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
950 self.track_for_cleanup(tempdir)
951 self.track_for_cleanup(self.workspacedir)
952 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
953 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
954 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
955 self.assertExists(os.path.join(tempdir, 'Cargo.toml'), 'Extracted source could not be found')
956 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
957 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'zvariant_*.bbappend'))
958 self.assertTrue(matches, 'bbappend not created')
959 # Test devtool status
960 result = runCmd('devtool status')
961 self.assertIn(testrecipe, result.output)
962 self.assertIn(tempdir, result.output)
963 # Check git repo
964 self._check_src_repo(tempdir)
965 # Check that the patch is correctly applied
966 # last commit message in the tree must contain
967 # %% original patch: <patchname>
968 # ..
969 patchname = None
970 for uri in src_uri:
971 if uri.startswith('file://') and '.patch' in uri:
972 patchname = uri.replace("file://", "").partition('.patch')[0] + '.patch'
973 self.assertIsNotNone(patchname)
974 result = runCmd('git -C %s log -1' % tempdir)
975 self.assertIn("%%%% original patch: %s" % patchname, result.output)
976
977 # Configure the recipe to check that the git dependencies are correctly patched in cargo config
978 bitbake('-c configure %s' % testrecipe)
979
980 cargo_config_path = os.path.join(cargo_home, 'config')
981 with open(cargo_config_path, "r") as f:
982 cargo_config_contents = [line.strip('\n') for line in f.readlines()]
983
984 # Get back git dependencies of the recipe (ignoring the main one)
985 # and check that they are all correctly patched to be fetched locally
986 git_deps = [uri for uri in src_uri if uri.startswith("git://")][1:]
987 for git_dep in git_deps:
988 raw_url, _, raw_parms = git_dep.partition(";")
989 parms = {}
990 for parm in raw_parms.split(";"):
991 name_parm, _, value_parm = parm.partition('=')
992 parms[name_parm]=value_parm
993 self.assertIn('protocol', parms, 'git dependencies uri should contain the "protocol" parameter')
994 self.assertIn('name', parms, 'git dependencies uri should contain the "name" parameter')
995 self.assertIn('destsuffix', parms, 'git dependencies uri should contain the "destsuffix" parameter')
996 self.assertIn('type', parms, 'git dependencies uri should contain the "type" parameter')
997 self.assertEqual(parms['type'], 'git-dependency', 'git dependencies uri should have "type=git-dependency"')
998 raw_url = raw_url.replace("git://", '%s://' % parms['protocol'])
999 patch_line = '[patch."%s"]' % raw_url
1000 path_patched = os.path.join(workdir, parms['destsuffix'])
1001 path_override_line = '%s = { path = "%s" }' % (parms['name'], path_patched)
1002 # Would have been better to use tomllib to read this file :/
1003 self.assertIn(patch_line, cargo_config_contents)
1004 self.assertIn(path_override_line, cargo_config_contents)
1005
1006 # Try to package the recipe
1007 bitbake('-c package_qa %s' % testrecipe)
1008
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001009 def test_devtool_modify_localfiles(self):
1010 # Check preconditions
1011 testrecipe = 'lighttpd'
1012 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
1013 foundlocal = False
1014 for item in src_uri:
1015 if item.startswith('file://') and '.patch' not in item:
1016 foundlocal = True
1017 break
1018 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
1019 # Clean up anything in the workdir/sysroot/sstate cache
1020 bitbake('%s -c cleansstate' % testrecipe)
1021 # Try modifying a recipe
1022 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1023 self.track_for_cleanup(tempdir)
1024 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001025 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001026 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001027 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1028 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
1029 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
1030 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
1031 self.assertTrue(matches, 'bbappend not created')
1032 # Test devtool status
1033 result = runCmd('devtool status')
1034 self.assertIn(testrecipe, result.output)
1035 self.assertIn(tempdir, result.output)
1036 # Try building
1037 bitbake(testrecipe)
1038
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001039 def test_devtool_modify_virtual(self):
1040 # Try modifying a virtual recipe
1041 virtrecipe = 'virtual/make'
1042 realrecipe = 'make'
1043 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1044 self.track_for_cleanup(tempdir)
1045 self.track_for_cleanup(self.workspacedir)
1046 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1047 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
1048 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1049 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
1050 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
1051 self.assertTrue(matches, 'bbappend not created %s' % result.output)
1052 # Test devtool status
1053 result = runCmd('devtool status')
1054 self.assertNotIn(virtrecipe, result.output)
1055 self.assertIn(realrecipe, result.output)
1056 # Check git repo
1057 self._check_src_repo(tempdir)
1058 # This is probably sufficient
1059
Andrew Geisslerf0343792020-11-18 10:42:21 -06001060 def test_devtool_modify_overrides(self):
1061 # Try modifying a recipe with patches in overrides
1062 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1063 self.track_for_cleanup(tempdir)
1064 self.track_for_cleanup(self.workspacedir)
1065 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1066 result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
1067
1068 self._check_src_repo(tempdir)
1069 source = os.path.join(tempdir, "source")
1070 def check(branch, expected):
1071 runCmd('git -C %s checkout %s' % (tempdir, branch))
1072 with open(source, "rt") as f:
1073 content = f.read()
1074 self.assertEquals(content, expected)
1075 check('devtool', 'This is a test for something\n')
1076 check('devtool-no-overrides', 'This is a test for something\n')
1077 check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
1078 check('devtool-override-qemux86', 'This is a test for qemux86\n')
1079
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001080class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001081
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001082 def test_devtool_update_recipe(self):
1083 # Check preconditions
1084 testrecipe = 'minicom'
1085 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1086 recipefile = bb_vars['FILE']
1087 src_uri = bb_vars['SRC_URI']
1088 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1089 self._check_repo_status(os.path.dirname(recipefile), [])
1090 # First, modify a recipe
1091 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1092 self.track_for_cleanup(tempdir)
1093 self.track_for_cleanup(self.workspacedir)
1094 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1095 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1096 # We don't use -x here so that we test the behaviour of devtool modify without it
1097 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
1098 # Check git repo
1099 self._check_src_repo(tempdir)
1100 # Add a couple of commits
1101 # FIXME: this only tests adding, need to also test update and remove
1102 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
1103 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
1104 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1105 result = runCmd('git add devtool-new-file', cwd=tempdir)
1106 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1107 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1108 result = runCmd('devtool update-recipe %s' % testrecipe)
1109 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1110 ('??', '.*/0001-Change-the-README.patch$'),
1111 ('??', '.*/0002-Add-a-new-file.patch$')]
1112 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1113
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001114 def test_devtool_update_recipe_git(self):
1115 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001116 testrecipe = 'mtd-utils-selftest'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001117 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1118 recipefile = bb_vars['FILE']
1119 src_uri = bb_vars['SRC_URI']
1120 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1121 patches = []
1122 for entry in src_uri.split():
1123 if entry.startswith('file://') and entry.endswith('.patch'):
1124 patches.append(entry[7:].split(';')[0])
1125 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
1126 self._check_repo_status(os.path.dirname(recipefile), [])
1127 # First, modify a recipe
1128 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1129 self.track_for_cleanup(tempdir)
1130 self.track_for_cleanup(self.workspacedir)
1131 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1132 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1133 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1134 # Check git repo
1135 self._check_src_repo(tempdir)
1136 # Add a couple of commits
1137 # FIXME: this only tests adding, need to also test update and remove
1138 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
1139 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
1140 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1141 result = runCmd('git add devtool-new-file', cwd=tempdir)
1142 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1143 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1144 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
1145 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
1146 [(' D', '.*/%s$' % patch) for patch in patches]
1147 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1148
1149 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +00001150 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001151 srcurilines = src_uri.split()
1152 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
1153 srcurilines.append('"')
1154 removelines = ['SRCREV = ".*"'] + srcurilines
Andrew Geissler615f2f12022-07-15 14:00:58 -05001155 self._check_diff(result.output, addlines, removelines)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001156 # Now try with auto mode
1157 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
1158 result = runCmd('devtool update-recipe %s' % testrecipe)
1159 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
1160 topleveldir = result.output.strip()
1161 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
1162 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
1163 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
1164 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
1165 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1166
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001167 def test_devtool_update_recipe_append(self):
1168 # Check preconditions
1169 testrecipe = 'mdadm'
1170 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1171 recipefile = bb_vars['FILE']
1172 src_uri = bb_vars['SRC_URI']
1173 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1174 self._check_repo_status(os.path.dirname(recipefile), [])
1175 # First, modify a recipe
1176 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1177 tempsrcdir = os.path.join(tempdir, 'source')
1178 templayerdir = os.path.join(tempdir, 'layer')
1179 self.track_for_cleanup(tempdir)
1180 self.track_for_cleanup(self.workspacedir)
1181 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1182 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1183 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1184 # Check git repo
1185 self._check_src_repo(tempsrcdir)
1186 # Add a commit
1187 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
1188 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1189 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1190 # Create a temporary layer and add it to bblayers.conf
1191 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
1192 # Create the bbappend
1193 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1194 self.assertNotIn('WARNING:', result.output)
1195 # Check recipe is still clean
1196 self._check_repo_status(os.path.dirname(recipefile), [])
1197 # Check bbappend was created
1198 splitpath = os.path.dirname(recipefile).split(os.sep)
1199 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1200 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1201 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
1202 self.assertExists(patchfile, 'Patch file not created')
1203
1204 # Check bbappend contents
Patrick Williams213cb262021-08-07 19:21:33 -05001205 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001206 '\n',
1207 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
1208 '\n']
1209 with open(bbappendfile, 'r') as f:
1210 self.assertEqual(expectedlines, f.readlines())
1211
1212 # Check we can run it again and bbappend isn't modified
1213 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1214 with open(bbappendfile, 'r') as f:
1215 self.assertEqual(expectedlines, f.readlines())
1216 # Drop new commit and check patch gets deleted
1217 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1218 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1219 self.assertNotExists(patchfile, 'Patch file not deleted')
Patrick Williams213cb262021-08-07 19:21:33 -05001220 expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001221 '\n']
1222 with open(bbappendfile, 'r') as f:
1223 self.assertEqual(expectedlines2, f.readlines())
1224 # Put commit back and check we can run it if layer isn't in bblayers.conf
1225 os.remove(bbappendfile)
1226 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1227 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1228 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1229 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1230 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
1231 with open(bbappendfile, 'r') as f:
1232 self.assertEqual(expectedlines, f.readlines())
1233 # Deleting isn't expected to work under these circumstances
1234
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001235 def test_devtool_update_recipe_append_git(self):
1236 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001237 testrecipe = 'mtd-utils-selftest'
Andrew Geissler517393d2023-01-13 08:55:19 -06001238 bb_vars = get_bb_vars(['FILE', 'SRC_URI', 'LAYERSERIES_CORENAMES'], testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001239 recipefile = bb_vars['FILE']
1240 src_uri = bb_vars['SRC_URI']
Andrew Geissler517393d2023-01-13 08:55:19 -06001241 corenames = bb_vars['LAYERSERIES_CORENAMES']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001242 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1243 for entry in src_uri.split():
1244 if entry.startswith('git://'):
1245 git_uri = entry
1246 break
1247 self._check_repo_status(os.path.dirname(recipefile), [])
1248 # First, modify a recipe
1249 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1250 tempsrcdir = os.path.join(tempdir, 'source')
1251 templayerdir = os.path.join(tempdir, 'layer')
1252 self.track_for_cleanup(tempdir)
1253 self.track_for_cleanup(self.workspacedir)
1254 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1255 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1256 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1257 # Check git repo
1258 self._check_src_repo(tempsrcdir)
1259 # Add a commit
1260 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
1261 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1262 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1263 # Create a temporary layer
1264 os.makedirs(os.path.join(templayerdir, 'conf'))
1265 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
1266 f.write('BBPATH .= ":${LAYERDIR}"\n')
1267 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
1268 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
1269 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
1270 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
1271 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Andrew Geissler517393d2023-01-13 08:55:19 -06001272 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "%s"\n' % corenames)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001273 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
1274 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
1275 # Create the bbappend
1276 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1277 self.assertNotIn('WARNING:', result.output)
1278 # Check recipe is still clean
1279 self._check_repo_status(os.path.dirname(recipefile), [])
1280 # Check bbappend was created
1281 splitpath = os.path.dirname(recipefile).split(os.sep)
1282 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1283 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1284 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1285
1286 # Check bbappend contents
1287 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1288 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1289 '\n',
1290 'SRC_URI = "%s"\n' % git_uri,
1291 '\n'])
1292 with open(bbappendfile, 'r') as f:
1293 self.assertEqual(expectedlines, set(f.readlines()))
1294
1295 # Check we can run it again and bbappend isn't modified
1296 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1297 with open(bbappendfile, 'r') as f:
1298 self.assertEqual(expectedlines, set(f.readlines()))
1299 # Drop new commit and check SRCREV changes
1300 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1301 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1302 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1303 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1304 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1305 '\n',
1306 'SRC_URI = "%s"\n' % git_uri,
1307 '\n'])
1308 with open(bbappendfile, 'r') as f:
1309 self.assertEqual(expectedlines, set(f.readlines()))
1310 # Put commit back and check we can run it if layer isn't in bblayers.conf
1311 os.remove(bbappendfile)
1312 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1313 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1314 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1315 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1316 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1317 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1318 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1319 '\n',
1320 'SRC_URI = "%s"\n' % git_uri,
1321 '\n'])
1322 with open(bbappendfile, 'r') as f:
1323 self.assertEqual(expectedlines, set(f.readlines()))
1324 # Deleting isn't expected to work under these circumstances
1325
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001326 def test_devtool_update_recipe_local_files(self):
1327 """Check that local source files are copied over instead of patched"""
1328 testrecipe = 'makedevs'
1329 recipefile = get_bb_var('FILE', testrecipe)
1330 # Setup srctree for modifying the recipe
1331 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1332 self.track_for_cleanup(tempdir)
1333 self.track_for_cleanup(self.workspacedir)
1334 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1335 # (don't bother with cleaning the recipe on teardown, we won't be
1336 # building it)
1337 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1338 # Check git repo
1339 self._check_src_repo(tempdir)
1340 # Try building just to ensure we haven't broken that
1341 bitbake("%s" % testrecipe)
1342 # Edit / commit local source
1343 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1344 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1345 runCmd('echo "Bar" > new-file', cwd=tempdir)
1346 runCmd('git add new-file', cwd=tempdir)
1347 runCmd('git commit -m "Add new file"', cwd=tempdir)
1348 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1349 os.path.dirname(recipefile))
1350 runCmd('devtool update-recipe %s' % testrecipe)
1351 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1352 (' M', '.*/makedevs/makedevs.c$'),
1353 ('??', '.*/makedevs/new-local$'),
1354 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1355 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1356
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001357 def test_devtool_update_recipe_local_files_2(self):
1358 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001359 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001360 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001361 recipedir = os.path.dirname(recipefile)
1362 result = runCmd('git status --porcelain .', cwd=recipedir)
1363 if result.output.strip():
1364 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001365 # Setup srctree for modifying the recipe
1366 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1367 self.track_for_cleanup(tempdir)
1368 self.track_for_cleanup(self.workspacedir)
1369 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1370 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1371 # Check git repo
1372 self._check_src_repo(tempdir)
1373 # Add oe-local-files to Git
1374 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1375 runCmd('git add oe-local-files', cwd=tempdir)
1376 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1377 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001378 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001379 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001380 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001381 runCmd('git commit -m"Remove file"', cwd=tempdir)
1382 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1383 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1384 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1385 runCmd('echo "Gar" > new-file', cwd=tempdir)
1386 runCmd('git add new-file', cwd=tempdir)
1387 runCmd('git commit -m "Add new file"', cwd=tempdir)
1388 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1389 os.path.dirname(recipefile))
1390 # Checkout unmodified file to working copy -> devtool should still pick
1391 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001392 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001393 runCmd('devtool update-recipe %s' % testrecipe)
1394 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001395 (' M', '.*/file1$'),
1396 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001397 ('??', '.*/new-local$'),
1398 ('??', '.*/0001-Add-new-file.patch$')]
1399 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1400
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001401 def test_devtool_update_recipe_with_gitignore(self):
1402 # First, modify the recipe
1403 testrecipe = 'devtool-test-ignored'
1404 bb_vars = get_bb_vars(['FILE'], testrecipe)
1405 recipefile = bb_vars['FILE']
1406 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1407 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
1408 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1409 self.track_for_cleanup(tempdir)
1410 self.track_for_cleanup(self.workspacedir)
1411 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1412 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1413 result = runCmd('devtool modify %s' % testrecipe)
1414 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1415 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1416 # Check recipe got changed as expected
1417 with open(newpatchfile, 'r') as f:
1418 desiredlines = f.readlines()
1419 with open(patchfile, 'r') as f:
1420 newlines = f.readlines()
1421 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1422 # which changes the metadata subject which is added into the patch, but keep
1423 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1424 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1425 self.assertEqual(desiredlines[5:], newlines[5:])
1426
1427 def test_devtool_update_recipe_long_filename(self):
1428 # First, modify the recipe
1429 testrecipe = 'devtool-test-long-filename'
1430 bb_vars = get_bb_vars(['FILE'], testrecipe)
1431 recipefile = bb_vars['FILE']
1432 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1433 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1434 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1435 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1436 self.track_for_cleanup(tempdir)
1437 self.track_for_cleanup(self.workspacedir)
1438 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1439 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1440 result = runCmd('devtool modify %s' % testrecipe)
1441 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1442 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1443 # Check recipe got changed as expected
1444 with open(newpatchfile, 'r') as f:
1445 desiredlines = f.readlines()
1446 with open(patchfile, 'r') as f:
1447 newlines = f.readlines()
1448 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1449 # which changes the metadata subject which is added into the patch, but keep
1450 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1451 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1452 self.assertEqual(desiredlines[5:], newlines[5:])
1453
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001454 def test_devtool_update_recipe_local_files_3(self):
1455 # First, modify the recipe
1456 testrecipe = 'devtool-test-localonly'
1457 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1458 recipefile = bb_vars['FILE']
1459 src_uri = bb_vars['SRC_URI']
1460 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1461 self.track_for_cleanup(tempdir)
1462 self.track_for_cleanup(self.workspacedir)
1463 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1464 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1465 result = runCmd('devtool modify %s' % testrecipe)
1466 # Modify one file
1467 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1468 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1469 result = runCmd('devtool update-recipe %s' % testrecipe)
1470 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1471 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1472
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001473 def test_devtool_update_recipe_local_patch_gz(self):
1474 # First, modify the recipe
1475 testrecipe = 'devtool-test-patch-gz'
1476 if get_bb_var('DISTRO') == 'poky-tiny':
1477 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1478 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1479 recipefile = bb_vars['FILE']
1480 src_uri = bb_vars['SRC_URI']
1481 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1482 self.track_for_cleanup(tempdir)
1483 self.track_for_cleanup(self.workspacedir)
1484 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1485 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1486 result = runCmd('devtool modify %s' % testrecipe)
1487 # Modify one file
1488 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1489 runCmd('echo "Another line" >> README', cwd=srctree)
1490 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1491 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1492 result = runCmd('devtool update-recipe %s' % testrecipe)
1493 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1494 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1495 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1496 result = runCmd('file %s' % patch_gz)
1497 if 'gzip compressed data' not in result.output:
1498 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1499
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001500 def test_devtool_update_recipe_local_files_subdir(self):
1501 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1502 # SRC_URI such that it overwrites a file that was in an archive that
1503 # was also in SRC_URI
1504 # First, modify the recipe
1505 testrecipe = 'devtool-test-subdir'
1506 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1507 recipefile = bb_vars['FILE']
1508 src_uri = bb_vars['SRC_URI']
1509 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1510 self.track_for_cleanup(tempdir)
1511 self.track_for_cleanup(self.workspacedir)
1512 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1513 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1514 result = runCmd('devtool modify %s' % testrecipe)
1515 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1516 self.assertExists(testfile, 'Extracted source could not be found')
1517 with open(testfile, 'r') as f:
1518 contents = f.read().rstrip()
1519 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1520 # Test devtool update-recipe without modifying any files
1521 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1522 result = runCmd('devtool update-recipe %s' % testrecipe)
1523 expected_status = []
1524 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1525
Andrew Geissler615f2f12022-07-15 14:00:58 -05001526 def test_devtool_finish_modify_git_subdir(self):
1527 # Check preconditions
1528 testrecipe = 'dos2unix'
Patrick Williams520786c2023-06-25 16:20:36 -05001529 self.append_config('ERROR_QA:remove:pn-dos2unix = "patch-status"\n')
Andrew Geissler615f2f12022-07-15 14:00:58 -05001530 bb_vars = get_bb_vars(['SRC_URI', 'S', 'WORKDIR', 'FILE'], testrecipe)
1531 self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe)
1532 workdir_git = '%s/git/' % bb_vars['WORKDIR']
1533 if not bb_vars['S'].startswith(workdir_git):
1534 self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe)
1535 subdir = bb_vars['S'].split(workdir_git, 1)[1]
1536 # Clean up anything in the workdir/sysroot/sstate cache
1537 bitbake('%s -c cleansstate' % testrecipe)
1538 # Try modifying a recipe
1539 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1540 self.track_for_cleanup(tempdir)
1541 self.track_for_cleanup(self.workspacedir)
1542 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1543 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1544 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1545 testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c')
1546 self.assertExists(testsrcfile, 'Extracted source could not be found')
1547 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
1548 self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo')
1549 # Check git repo
1550 self._check_src_repo(tempdir)
1551 # Modify file
1552 runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile)
1553 result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir)
1554 # Now try updating original recipe
1555 recipefile = bb_vars['FILE']
1556 recipedir = os.path.dirname(recipefile)
1557 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1558 result = runCmd('devtool update-recipe %s' % testrecipe)
1559 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1560 ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))]
1561 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1562 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
1563 removelines = ['SRC_URI = "git://.*"']
1564 addlines = [
1565 'SRC_URI = "git://.* \\\\',
1566 'file://0001-Add-a-comment.patch;patchdir=.. \\\\',
1567 '"'
1568 ]
1569 self._check_diff(result.output, addlines, removelines)
1570 # Put things back so we can run devtool finish on a different layer
1571 runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1572 # Run devtool finish
1573 res = re.search('recipes-.*', recipedir)
1574 self.assertTrue(res, 'Unable to find recipe subdirectory')
1575 recipesubdir = res[0]
1576 self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir))
1577 result = runCmd('devtool finish %s meta-selftest' % testrecipe)
1578 # Check bbappend file contents
1579 appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe)
1580 with open(appendfn, 'r') as f:
1581 appendlines = f.readlines()
1582 expected_appendlines = [
1583 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
1584 '\n',
1585 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n',
1586 '\n'
1587 ]
1588 self.assertEqual(appendlines, expected_appendlines)
1589 self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch'))
1590 # Try building
1591 bitbake('%s -c patch' % testrecipe)
1592
1593
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001594class DevtoolExtractTests(DevtoolBase):
1595
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001596 def test_devtool_extract(self):
1597 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1598 # Try devtool extract
1599 self.track_for_cleanup(tempdir)
1600 self.track_for_cleanup(self.workspacedir)
1601 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1602 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1603 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1604 self._check_src_repo(tempdir)
1605
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001606 def test_devtool_extract_virtual(self):
1607 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1608 # Try devtool extract
1609 self.track_for_cleanup(tempdir)
1610 self.track_for_cleanup(self.workspacedir)
1611 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1612 result = runCmd('devtool extract virtual/make %s' % tempdir)
1613 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1614 self._check_src_repo(tempdir)
1615
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001616 def test_devtool_reset_all(self):
1617 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1618 self.track_for_cleanup(tempdir)
1619 self.track_for_cleanup(self.workspacedir)
1620 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1621 testrecipe1 = 'mdadm'
1622 testrecipe2 = 'cronie'
1623 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1624 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1625 result = runCmd('devtool build %s' % testrecipe1)
1626 result = runCmd('devtool build %s' % testrecipe2)
1627 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1628 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1629 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1630 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1631 result = runCmd('devtool reset -a')
1632 self.assertIn(testrecipe1, result.output)
1633 self.assertIn(testrecipe2, result.output)
1634 result = runCmd('devtool status')
1635 self.assertNotIn(testrecipe1, result.output)
1636 self.assertNotIn(testrecipe2, result.output)
1637 matches1 = glob.glob(stampprefix1 + '*')
1638 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1639 matches2 = glob.glob(stampprefix2 + '*')
1640 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1641
Patrick Williams45852732022-04-02 08:58:32 -05001642 @OETestTag("runqemu")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001643 def test_devtool_deploy_target(self):
Andrew Geissler220dafd2023-10-04 10:18:08 -05001644 self._check_runqemu_prerequisites()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001645 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1646 # Definitions
1647 testrecipe = 'mdadm'
1648 testfile = '/sbin/mdadm'
1649 testimage = 'oe-selftest-image'
1650 testcommand = '/sbin/mdadm --help'
1651 # Build an image to run
1652 bitbake("%s qemu-native qemu-helper-native" % testimage)
1653 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1654 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1655 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1656 # Clean recipe so the first deploy will fail
1657 bitbake("%s -c clean" % testrecipe)
1658 # Try devtool modify
1659 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1660 self.track_for_cleanup(tempdir)
1661 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001662 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001663 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001664 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1665 # Test that deploy-target at this point fails (properly)
1666 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1667 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1668 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1669 result = runCmd('devtool build %s' % testrecipe)
1670 # First try a dry-run of deploy-target
1671 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1672 self.assertIn(' %s' % testfile, result.output)
1673 # Boot the image
1674 with runqemu(testimage) as qemu:
1675 # Now really test deploy-target
1676 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1677 # Run a test command to see if it was installed properly
1678 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1679 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1680 # Check if it deployed all of the files with the right ownership/perms
1681 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1682 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1683 installdir = bb_vars['D']
1684 fakerootenv = bb_vars['FAKEROOTENV']
1685 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001686 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001687 filelist1 = self._process_ls_output(result.output)
1688
1689 # Now look on the target
1690 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1691 self.track_for_cleanup(tempdir2)
1692 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1693 with open(tmpfilelist, 'w') as f:
1694 for line in filelist1:
1695 splitline = line.split()
1696 f.write(splitline[-1] + '\n')
1697 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1698 filelist2 = self._process_ls_output(result.output)
1699 filelist1.sort(key=lambda item: item.split()[-1])
1700 filelist2.sort(key=lambda item: item.split()[-1])
1701 self.assertEqual(filelist1, filelist2)
1702 # Test undeploy-target
1703 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1704 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1705 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1706
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001707 def test_devtool_build_image(self):
1708 """Test devtool build-image plugin"""
1709 # Check preconditions
1710 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1711 image = 'core-image-minimal'
1712 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001713 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001714 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001715 bitbake('%s -c clean' % image)
1716 # Add target and native recipes to workspace
1717 recipes = ['mdadm', 'parted-native']
1718 for recipe in recipes:
1719 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1720 self.track_for_cleanup(tempdir)
1721 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1722 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1723 # Try to build image
1724 result = runCmd('devtool build-image %s' % image)
1725 self.assertNotEqual(result, 0, 'devtool build-image failed')
1726 # Check if image contains expected packages
1727 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1728 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1729 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1730 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1731 for line in f:
1732 splitval = line.split()
1733 if splitval:
1734 pkg = splitval[0]
1735 if pkg in reqpkgs:
1736 reqpkgs.remove(pkg)
1737 if reqpkgs:
1738 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1739
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001740class DevtoolUpgradeTests(DevtoolBase):
1741
Patrick Williams45852732022-04-02 08:58:32 -05001742 def setUp(self):
1743 super().setUp()
1744 try:
1745 runCmd("git config --global user.name")
1746 runCmd("git config --global user.email")
1747 except:
1748 self.skip("Git user.name and user.email must be set")
1749
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001750 def test_devtool_upgrade(self):
1751 # Check preconditions
1752 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1753 self.track_for_cleanup(self.workspacedir)
1754 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1755 # Check parameters
1756 result = runCmd('devtool upgrade -h')
1757 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1758 self.assertIn(param, result.output)
1759 # For the moment, we are using a real recipe.
1760 recipe = 'devtool-upgrade-test1'
1761 version = '1.6.0'
1762 oldrecipefile = get_bb_var('FILE', recipe)
1763 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1764 self.track_for_cleanup(tempdir)
1765 # Check that recipe is not already under devtool control
1766 result = runCmd('devtool status')
1767 self.assertNotIn(recipe, result.output)
1768 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1769 # we are downgrading instead of upgrading.
1770 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1771 # Check if srctree at least is populated
1772 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1773 # Check new recipe subdirectory is present
1774 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1775 # Check new recipe file is present
1776 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1777 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1778 # Check devtool status and make sure recipe is present
1779 result = runCmd('devtool status')
1780 self.assertIn(recipe, result.output)
1781 self.assertIn(tempdir, result.output)
1782 # Check recipe got changed as expected
1783 with open(oldrecipefile + '.upgraded', 'r') as f:
1784 desiredlines = f.readlines()
1785 with open(newrecipefile, 'r') as f:
1786 newlines = f.readlines()
1787 self.assertEqual(desiredlines, newlines)
1788 # Check devtool reset recipe
1789 result = runCmd('devtool reset %s -n' % recipe)
1790 result = runCmd('devtool status')
1791 self.assertNotIn(recipe, result.output)
1792 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1793
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001794 def test_devtool_upgrade_git(self):
1795 # Check preconditions
1796 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1797 self.track_for_cleanup(self.workspacedir)
1798 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1799 recipe = 'devtool-upgrade-test2'
1800 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1801 oldrecipefile = get_bb_var('FILE', recipe)
1802 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1803 self.track_for_cleanup(tempdir)
1804 # Check that recipe is not already under devtool control
1805 result = runCmd('devtool status')
1806 self.assertNotIn(recipe, result.output)
1807 # Check upgrade
1808 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1809 # Check if srctree at least is populated
1810 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1811 # Check new recipe file is present
1812 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1813 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1814 # Check devtool status and make sure recipe is present
1815 result = runCmd('devtool status')
1816 self.assertIn(recipe, result.output)
1817 self.assertIn(tempdir, result.output)
1818 # Check recipe got changed as expected
1819 with open(oldrecipefile + '.upgraded', 'r') as f:
1820 desiredlines = f.readlines()
1821 with open(newrecipefile, 'r') as f:
1822 newlines = f.readlines()
1823 self.assertEqual(desiredlines, newlines)
1824 # Check devtool reset recipe
1825 result = runCmd('devtool reset %s -n' % recipe)
1826 result = runCmd('devtool status')
1827 self.assertNotIn(recipe, result.output)
1828 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1829
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001830 def test_devtool_layer_plugins(self):
1831 """Test that devtool can use plugins from other layers.
1832
1833 This test executes the selftest-reverse command from meta-selftest."""
1834
1835 self.track_for_cleanup(self.workspacedir)
1836 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1837
1838 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1839 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1840 self.assertEqual(result.output, s[::-1])
1841
1842 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1843 dstdir = basedstdir
1844 self.assertExists(dstdir)
1845 for p in paths:
1846 dstdir = os.path.join(dstdir, p)
1847 if not os.path.exists(dstdir):
1848 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001849 if p == "lib":
1850 # Can race with other tests
1851 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1852 else:
1853 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001854 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1855 if srcfile != dstfile:
1856 shutil.copy(srcfile, dstfile)
1857 self.track_for_cleanup(dstfile)
1858
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001859 def test_devtool_load_plugin(self):
1860 """Test that devtool loads only the first found plugin in BBPATH."""
1861
1862 self.track_for_cleanup(self.workspacedir)
1863 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1864
1865 devtool = runCmd("which devtool")
1866 fromname = runCmd("devtool --quiet pluginfile")
1867 srcfile = fromname.output
1868 bbpath = get_bb_var('BBPATH')
1869 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1870 plugincontent = []
1871 with open(srcfile) as fh:
1872 plugincontent = fh.readlines()
1873 try:
1874 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1875 for path in searchpath:
1876 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1877 result = runCmd("devtool --quiet count")
1878 self.assertEqual(result.output, '1')
1879 result = runCmd("devtool --quiet multiloaded")
1880 self.assertEqual(result.output, "no")
1881 for path in searchpath:
1882 result = runCmd("devtool --quiet bbdir")
1883 self.assertEqual(result.output, path)
1884 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1885 finally:
1886 with open(srcfile, 'w') as fh:
1887 fh.writelines(plugincontent)
1888
1889 def _setup_test_devtool_finish_upgrade(self):
1890 # Check preconditions
1891 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1892 self.track_for_cleanup(self.workspacedir)
1893 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1894 # Use a "real" recipe from meta-selftest
1895 recipe = 'devtool-upgrade-test1'
1896 oldversion = '1.5.3'
1897 newversion = '1.6.0'
1898 oldrecipefile = get_bb_var('FILE', recipe)
1899 recipedir = os.path.dirname(oldrecipefile)
1900 result = runCmd('git status --porcelain .', cwd=recipedir)
1901 if result.output.strip():
1902 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1903 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1904 self.track_for_cleanup(tempdir)
1905 # Check that recipe is not already under devtool control
1906 result = runCmd('devtool status')
1907 self.assertNotIn(recipe, result.output)
1908 # Do the upgrade
1909 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1910 # Check devtool status and make sure recipe is present
1911 result = runCmd('devtool status')
1912 self.assertIn(recipe, result.output)
1913 self.assertIn(tempdir, result.output)
1914 # Make a change to the source
1915 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1916 result = runCmd('git status --porcelain', cwd=tempdir)
1917 self.assertIn('M src/pv/number.c', result.output)
1918 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1919 # Check if patch is there
1920 recipedir = os.path.dirname(oldrecipefile)
1921 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1922 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001923 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001924 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001925 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1926 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001927
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001928 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001929 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001930 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1931 self.assertIn('/meta-selftest/', recipedir)
1932 # Try finish to the original layer
1933 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1934 result = runCmd('devtool finish %s meta-selftest' % recipe)
1935 result = runCmd('devtool status')
1936 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1937 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1938 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1939 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001940 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 -05001941 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1942 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1943 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1944 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 -05001945 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 -05001946 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 -05001947 with open(newrecipefile, 'r') as f:
1948 newcontent = f.read()
1949 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1950 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1951 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1952 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1953
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001954
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001955 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001956 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001957 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1958 self.assertIn('/meta-selftest/', recipedir)
1959 # Try finish to a different layer - should create a bbappend
1960 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1961 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1962 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1963 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1964 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1965 self.track_for_cleanup(newrecipedir)
1966 result = runCmd('devtool finish %s oe-core' % recipe)
1967 result = runCmd('devtool status')
1968 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1969 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1970 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1971 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001972 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001973 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1974 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1975 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 -05001976 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 -05001977 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 -05001978 with open(newrecipefile, 'r') as f:
1979 newcontent = f.read()
1980 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1981 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1982 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1983 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 -05001984
1985 def _setup_test_devtool_finish_modify(self):
1986 # Check preconditions
1987 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1988 # Try modifying a recipe
1989 self.track_for_cleanup(self.workspacedir)
1990 recipe = 'mdadm'
1991 oldrecipefile = get_bb_var('FILE', recipe)
1992 recipedir = os.path.dirname(oldrecipefile)
1993 result = runCmd('git status --porcelain .', cwd=recipedir)
1994 if result.output.strip():
1995 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1996 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1997 self.track_for_cleanup(tempdir)
1998 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1999 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
2000 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2001 # Test devtool status
2002 result = runCmd('devtool status')
2003 self.assertIn(recipe, result.output)
2004 self.assertIn(tempdir, result.output)
2005 # Make a change to the source
2006 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
2007 result = runCmd('git status --porcelain', cwd=tempdir)
2008 self.assertIn('M maps.c', result.output)
2009 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
2010 for entry in os.listdir(recipedir):
2011 filesdir = os.path.join(recipedir, entry)
2012 if os.path.isdir(filesdir):
2013 break
2014 else:
2015 self.fail('Unable to find recipe files directory for %s' % recipe)
2016 return recipe, oldrecipefile, recipedir, filesdir
2017
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002018 def test_devtool_finish_modify_origlayer(self):
2019 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
2020 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
2021 self.assertIn('/meta/', recipedir)
2022 # Try finish to the original layer
2023 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2024 result = runCmd('devtool finish %s meta' % recipe)
2025 result = runCmd('devtool status')
2026 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2027 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2028 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
2029 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
2030 self._check_repo_status(recipedir, expected_status)
2031
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002032 def test_devtool_finish_modify_otherlayer(self):
2033 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
2034 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
2035 self.assertIn('/meta/', recipedir)
2036 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
2037 appenddir = os.path.join(get_test_layer(), relpth)
2038 self.track_for_cleanup(appenddir)
2039 # Try finish to the original layer
2040 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2041 result = runCmd('devtool finish %s meta-selftest' % recipe)
2042 result = runCmd('devtool status')
2043 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2044 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2045 result = runCmd('git status --porcelain .', cwd=recipedir)
2046 if result.output.strip():
2047 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
2048 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
2049 recipefn = recipefn.split('_')[0] + '_%'
2050 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
2051 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
2052 newdir = os.path.join(appenddir, recipe)
2053 files = os.listdir(newdir)
2054 foundpatch = None
2055 for fn in files:
2056 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
2057 foundpatch = fn
2058 if not foundpatch:
2059 self.fail('No patch file created next to bbappend')
2060 files.remove(foundpatch)
2061 if files:
2062 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
2063
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002064 def test_devtool_rename(self):
2065 # Check preconditions
2066 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
2067 self.track_for_cleanup(self.workspacedir)
2068 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
2069
2070 # First run devtool add
2071 # We already have this recipe in OE-Core, but that doesn't matter
2072 recipename = 'i2c-tools'
2073 recipever = '3.1.2'
2074 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
2075 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
2076 def add_recipe():
2077 result = runCmd('devtool add %s' % url)
2078 self.assertExists(recipefile, 'Expected recipe file not created')
2079 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
2080 checkvars = {}
2081 checkvars['S'] = None
2082 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2083 self._test_recipe_contents(recipefile, checkvars, [])
2084 add_recipe()
2085 # Now rename it - change both name and version
2086 newrecipename = 'mynewrecipe'
2087 newrecipever = '456'
2088 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
2089 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
2090 self.assertExists(newrecipefile, 'Recipe file not renamed')
2091 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2092 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
2093 self.assertExists(newsrctree, 'Source directory not renamed')
2094 checkvars = {}
2095 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
2096 checkvars['SRC_URI'] = url
2097 self._test_recipe_contents(newrecipefile, checkvars, [])
2098 # Try again - change just name this time
2099 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002100 add_recipe()
2101 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
2102 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
2103 self.assertExists(newrecipefile, 'Recipe file not renamed')
2104 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2105 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
2106 checkvars = {}
2107 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
2108 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2109 self._test_recipe_contents(newrecipefile, checkvars, [])
2110 # Try again - change just version this time
2111 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002112 add_recipe()
2113 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
2114 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
2115 self.assertExists(newrecipefile, 'Recipe file not renamed')
2116 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
2117 checkvars = {}
2118 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
2119 checkvars['SRC_URI'] = url
2120 self._test_recipe_contents(newrecipefile, checkvars, [])
2121
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002122 def test_devtool_virtual_kernel_modify(self):
2123 """
2124 Summary: The purpose of this test case is to verify that
2125 devtool modify works correctly when building
2126 the kernel.
2127 Dependencies: NA
2128 Steps: 1. Build kernel with bitbake.
2129 2. Save the config file generated.
2130 3. Clean the environment.
2131 4. Use `devtool modify virtual/kernel` to validate following:
2132 4.1 The source is checked out correctly.
2133 4.2 The resulting configuration is the same as
2134 what was get on step 2.
2135 4.3 The Kernel can be build correctly.
2136 4.4 Changes made on the source are reflected on the
2137 subsequent builds.
2138 4.5 Changes on the configuration are reflected on the
2139 subsequent builds
2140 Expected: devtool modify is able to checkout the source of the kernel
2141 and modification to the source and configurations are reflected
2142 when building the kernel.
Patrick Williams45852732022-04-02 08:58:32 -05002143 """
2144 kernel_provider = self.td['PREFERRED_PROVIDER_virtual/kernel']
2145
Andrew Geissler82c905d2020-04-13 13:39:40 -05002146 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002147 bitbake('%s -c clean' % kernel_provider)
2148 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2149 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
2150 self.track_for_cleanup(tempdir)
2151 self.track_for_cleanup(tempdir_cfg)
2152 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002153 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04002154 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002155 #Step 1
2156 #Here is just generated the config file instead of all the kernel to optimize the
2157 #time of executing this test case.
2158 bitbake('%s -c configure' % kernel_provider)
2159 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
2160 #Step 2
2161 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
2162 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
2163
2164 tmpconfig = os.path.join(tempdir_cfg, '.config')
2165 #Step 3
2166 bitbake('%s -c clean' % kernel_provider)
2167 #Step 4.1
2168 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
2169 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2170 #Step 4.2
2171 configfile = os.path.join(tempdir,'.config')
Patrick Williams45852732022-04-02 08:58:32 -05002172 runCmd('diff %s %s' % (tmpconfig, configfile))
2173
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002174 #Step 4.3
2175 #NOTE: virtual/kernel is mapped to kernel_provider
Patrick Williams45852732022-04-02 08:58:32 -05002176 runCmd('devtool build %s' % kernel_provider)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002177 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
2178 self.assertExists(kernelfile, 'Kernel was not build correctly')
2179
2180 #Modify the kernel source
Patrick Williams45852732022-04-02 08:58:32 -05002181 modfile = os.path.join(tempdir, 'init/version.c')
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002182 # Moved to uts.h in 6.1 onwards
2183 modfile2 = os.path.join(tempdir, 'include/linux/uts.h')
2184 runCmd("sed -i 's/Linux/LiNuX/g' %s %s" % (modfile, modfile2))
Patrick Williams45852732022-04-02 08:58:32 -05002185
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002186 #Modify the configuration
Patrick Williams45852732022-04-02 08:58:32 -05002187 codeconfigfile = os.path.join(tempdir, '.config.new')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002188 modconfopt = "CONFIG_SG_POOL=n"
Patrick Williams45852732022-04-02 08:58:32 -05002189 runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
2190
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002191 #Build again kernel with devtool
Patrick Williams45852732022-04-02 08:58:32 -05002192 runCmd('devtool build %s' % kernel_provider)
2193
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002194 #Step 4.4
Patrick Williams45852732022-04-02 08:58:32 -05002195 runCmd("grep '%s' %s" % ('LiNuX', kernelfile))
2196
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002197 #Step 4.5
Patrick Williams45852732022-04-02 08:58:32 -05002198 runCmd("grep %s %s" % (modconfopt, codeconfigfile))