blob: a2b77e528dee1dfd2ec67974693c3414fa43d5f3 [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
Patrick Williams92b42cb2022-09-03 06:53:57 -0500259 def _test_devtool_add_git_url(self, git_url, version, pn, resulting_src_uri):
260 self.track_for_cleanup(self.workspacedir)
261 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
262 result = runCmd('devtool add --version %s %s %s' % (version, pn, git_url))
263 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
264 # Check the recipe name is correct
265 recipefile = get_bb_var('FILE', pn)
266 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
267 self.assertIn(recipefile, result.output)
268 # Test devtool status
269 result = runCmd('devtool status')
270 self.assertIn(pn, result.output)
271 self.assertIn(recipefile, result.output)
272 checkvars = {}
273 checkvars['SRC_URI'] = resulting_src_uri
274 self._test_recipe_contents(recipefile, checkvars, [])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500275
Andrew Geissler595f6302022-01-24 19:11:47 +0000276class DevtoolBase(DevtoolTestCase):
277
278 @classmethod
279 def setUpClass(cls):
280 super(DevtoolBase, cls).setUpClass()
281 bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
282 cls.original_sstate = bb_vars['SSTATE_DIR']
283 cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
284 cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
285 cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
286 % cls.original_sstate)
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500287 cls.sstate_conf += ('BB_HASHSERVE_UPSTREAM = "hashserv.yocto.io:8687"\n')
Andrew Geissler595f6302022-01-24 19:11:47 +0000288
289 @classmethod
290 def tearDownClass(cls):
291 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
292 runCmd('rm -rf %s' % cls.devtool_sstate)
293 super(DevtoolBase, cls).tearDownClass()
294
295 def setUp(self):
296 """Test case setup function"""
297 super(DevtoolBase, self).setUp()
298 self.append_config(self.sstate_conf)
299
300
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500301class DevtoolTests(DevtoolBase):
302
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500303 def test_create_workspace(self):
304 # Check preconditions
305 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400306 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 -0400307 # remove conf/devtool.conf to avoid it corrupting tests
308 devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
309 self.track_for_cleanup(devtoolconf)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500310 # Try creating a workspace layer with a specific path
311 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
312 self.track_for_cleanup(tempdir)
313 result = runCmd('devtool create-workspace %s' % tempdir)
314 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
315 result = runCmd('bitbake-layers show-layers')
316 self.assertIn(tempdir, result.output)
317 # Try creating a workspace layer with the default path
318 self.track_for_cleanup(self.workspacedir)
319 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
320 result = runCmd('devtool create-workspace')
321 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
322 result = runCmd('bitbake-layers show-layers')
323 self.assertNotIn(tempdir, result.output)
324 self.assertIn(self.workspacedir, result.output)
325
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800326class DevtoolAddTests(DevtoolBase):
327
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500328 def test_devtool_add(self):
329 # Fetch source
330 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
331 self.track_for_cleanup(tempdir)
332 pn = 'pv'
333 pv = '1.5.3'
Andrew Geissler09209ee2020-12-13 08:44:15 -0600334 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500335 result = runCmd('wget %s' % url, cwd=tempdir)
336 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
337 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
338 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
339 # Test devtool add
340 self.track_for_cleanup(self.workspacedir)
341 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
342 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
343 result = runCmd('devtool add %s %s' % (pn, srcdir))
344 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
345 # Test devtool status
346 result = runCmd('devtool status')
347 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
348 self.assertIn(recipepath, result.output)
349 self.assertIn(srcdir, result.output)
350 # Test devtool find-recipe
351 result = runCmd('devtool -q find-recipe %s' % pn)
352 self.assertEqual(recipepath, result.output.strip())
353 # Test devtool edit-recipe
354 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
355 self.assertEqual('123 %s' % recipepath, result.output.strip())
356 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
357 bitbake('%s -c cleansstate' % pn)
358 # Test devtool build
359 result = runCmd('devtool build %s' % pn)
360 bb_vars = get_bb_vars(['D', 'bindir'], pn)
361 installdir = bb_vars['D']
362 self.assertTrue(installdir, 'Could not query installdir variable')
363 bindir = bb_vars['bindir']
364 self.assertTrue(bindir, 'Could not query bindir variable')
365 if bindir[0] == '/':
366 bindir = bindir[1:]
367 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
368
Andrew Geissler8f840682023-07-21 09:09:43 -0500369 def test_devtool_add_binary(self):
370 # Create a binary package containing a known test file
371 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
372 self.track_for_cleanup(tempdir)
373 pn = 'tst-bin'
374 pv = '1.0'
375 test_file_dir = "var/lib/%s/" % pn
376 test_file_name = "test_file"
377 test_file_content = "TEST CONTENT"
378 test_file_package_root = os.path.join(tempdir, pn)
379 test_file_dir_full = os.path.join(test_file_package_root, test_file_dir)
380 bb.utils.mkdirhier(test_file_dir_full)
381 with open(os.path.join(test_file_dir_full, test_file_name), "w") as f:
382 f.write(test_file_content)
383 bin_package_path = os.path.join(tempdir, "%s.tar.gz" % pn)
384 runCmd("tar czf %s -C %s ." % (bin_package_path, test_file_package_root))
385
386 # Test devtool add -b on the binary package
387 self.track_for_cleanup(self.workspacedir)
388 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
389 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
390 result = runCmd('devtool add -b %s %s' % (pn, bin_package_path))
391 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
392
393 # Build the resulting recipe
394 result = runCmd('devtool build %s' % pn)
395 installdir = get_bb_var('D', pn)
396 self.assertTrue(installdir, 'Could not query installdir variable')
397
398 # Check that a known file from the binary package has indeed been installed
399 self.assertTrue(os.path.isfile(os.path.join(installdir, test_file_dir, test_file_name)), '%s not found in D' % test_file_name)
400
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500401 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800402 # We need dbus built so that DEPENDS recognition works
403 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500404 # Fetch source from a remote URL, but do it outside of devtool
405 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
406 self.track_for_cleanup(tempdir)
407 pn = 'dbus-wait'
408 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
409 # We choose an https:// git URL here to check rewriting the URL works
410 url = 'https://git.yoctoproject.org/git/dbus-wait'
411 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
412 # instead of the directory name
413 result = runCmd('git clone %s noname' % url, cwd=tempdir)
414 srcdir = os.path.join(tempdir, 'noname')
415 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
416 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
417 # Test devtool add
418 self.track_for_cleanup(self.workspacedir)
419 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
420 # Don't specify a name since we should be able to auto-detect it
421 result = runCmd('devtool add %s' % srcdir)
422 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
423 # Check the recipe name is correct
424 recipefile = get_bb_var('FILE', pn)
425 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
426 self.assertIn(recipefile, result.output)
427 # Test devtool status
428 result = runCmd('devtool status')
429 self.assertIn(pn, result.output)
430 self.assertIn(srcdir, result.output)
431 self.assertIn(recipefile, result.output)
432 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000433 checkvars['LICENSE'] = 'GPL-2.0-only'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500434 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
435 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400436 checkvars['PV'] = '0.1+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000437 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500438 checkvars['SRCREV'] = srcrev
439 checkvars['DEPENDS'] = set(['dbus'])
440 self._test_recipe_contents(recipefile, checkvars, [])
441
Patrick Williams92b42cb2022-09-03 06:53:57 -0500442 def test_devtool_add_git_style1(self):
443 version = 'v3.1.0'
444 pn = 'mbedtls'
445 # this will trigger reformat_git_uri with branch parameter in url
446 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https'"
447 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https"
448 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
449
450 def test_devtool_add_git_style2(self):
451 version = 'v3.1.0'
452 pn = 'mbedtls'
453 # this will trigger reformat_git_uri with branch parameter in url
454 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;protocol=https'"
455 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;protocol=https;branch=master"
456 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
457
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500458 def test_devtool_add_library(self):
459 # Fetch source
460 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
461 self.track_for_cleanup(tempdir)
462 version = '1.1'
463 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
464 result = runCmd('wget %s' % url, cwd=tempdir)
465 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
466 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
467 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
468 # Test devtool add (and use -V so we test that too)
469 self.track_for_cleanup(self.workspacedir)
470 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
471 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
472 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
473 # Test devtool status
474 result = runCmd('devtool status')
475 self.assertIn('libftdi', result.output)
476 self.assertIn(srcdir, result.output)
477 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
478 bitbake('libftdi -c cleansstate')
479 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
480 # There's also the matter of it installing cmake files to a path we don't
481 # normally cover, which triggers the installed-vs-shipped QA test we have
482 # within do_package
483 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
484 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
485 with open(recipefile, 'a') as f:
Patrick Williams213cb262021-08-07 19:21:33 -0500486 f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500487 # We don't have the ability to pick up this dependency automatically yet...
488 f.write('\nDEPENDS += "libusb1"\n')
489 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
490 # Test devtool build
491 result = runCmd('devtool build libftdi')
492 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
493 staging_libdir = bb_vars['TESTLIBOUTPUT']
494 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
495 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)
496 # Test devtool reset
497 stampprefix = bb_vars['STAMP']
498 result = runCmd('devtool reset libftdi')
499 result = runCmd('devtool status')
500 self.assertNotIn('libftdi', result.output)
501 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
502 matches = glob.glob(stampprefix + '*')
503 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
504 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
505
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500506 def test_devtool_add_fetch(self):
507 # Fetch source
508 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
509 self.track_for_cleanup(tempdir)
510 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400511 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500512 testrecipe = 'python-markupsafe'
513 srcdir = os.path.join(tempdir, testrecipe)
514 # Test devtool add
515 self.track_for_cleanup(self.workspacedir)
516 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
517 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
518 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
519 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
520 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
521 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
522 # Test devtool status
523 result = runCmd('devtool status')
524 self.assertIn(testrecipe, result.output)
525 self.assertIn(srcdir, result.output)
526 # Check recipe
527 recipefile = get_bb_var('FILE', testrecipe)
528 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
529 checkvars = {}
530 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
531 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
532 self._test_recipe_contents(recipefile, checkvars, [])
533 # Try with version specified
534 result = runCmd('devtool reset -n %s' % testrecipe)
535 shutil.rmtree(srcdir)
536 fakever = '1.9'
537 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
538 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
539 # Test devtool status
540 result = runCmd('devtool status')
541 self.assertIn(testrecipe, result.output)
542 self.assertIn(srcdir, result.output)
543 # Check recipe
544 recipefile = get_bb_var('FILE', testrecipe)
545 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
546 checkvars = {}
547 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
548 checkvars['SRC_URI'] = url
549 self._test_recipe_contents(recipefile, checkvars, [])
Andrew Geissler615f2f12022-07-15 14:00:58 -0500550
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500551 def test_devtool_add_fetch_git(self):
552 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
553 self.track_for_cleanup(tempdir)
554 url = 'gitsm://git.yoctoproject.org/mraa'
Andrew Geissler595f6302022-01-24 19:11:47 +0000555 url_branch = '%s;branch=master' % url
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500556 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
557 testrecipe = 'mraa'
558 srcdir = os.path.join(tempdir, testrecipe)
559 # Test devtool add
560 self.track_for_cleanup(self.workspacedir)
561 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
562 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
563 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
564 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
565 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
566 # Test devtool status
567 result = runCmd('devtool status')
568 self.assertIn(testrecipe, result.output)
569 self.assertIn(srcdir, result.output)
570 # Check recipe
571 recipefile = get_bb_var('FILE', testrecipe)
572 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
573 checkvars = {}
574 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400575 checkvars['PV'] = '1.0+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000576 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500577 checkvars['SRCREV'] = '${AUTOREV}'
578 self._test_recipe_contents(recipefile, checkvars, [])
579 # Try with revision and version specified
580 result = runCmd('devtool reset -n %s' % testrecipe)
581 shutil.rmtree(srcdir)
582 url_rev = '%s;rev=%s' % (url, checkrev)
583 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
584 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
585 # Test devtool status
586 result = runCmd('devtool status')
587 self.assertIn(testrecipe, result.output)
588 self.assertIn(srcdir, result.output)
589 # Check recipe
590 recipefile = get_bb_var('FILE', testrecipe)
591 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
592 checkvars = {}
593 checkvars['S'] = '${WORKDIR}/git'
Andrew Geissler5082cc72023-09-11 08:41:39 -0400594 checkvars['PV'] = '1.5+git'
Andrew Geissler595f6302022-01-24 19:11:47 +0000595 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500596 checkvars['SRCREV'] = checkrev
597 self._test_recipe_contents(recipefile, checkvars, [])
598
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500599 def test_devtool_add_fetch_simple(self):
600 # Fetch source from a remote URL, auto-detecting name
601 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
602 self.track_for_cleanup(tempdir)
603 testver = '1.6.0'
604 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
605 testrecipe = 'pv'
606 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
607 # Test devtool add
608 self.track_for_cleanup(self.workspacedir)
609 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
610 result = runCmd('devtool add %s' % url)
611 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
612 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
613 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
614 # Test devtool status
615 result = runCmd('devtool status')
616 self.assertIn(testrecipe, result.output)
617 self.assertIn(srcdir, result.output)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500618 # Check recipedevtool add
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500619 recipefile = get_bb_var('FILE', testrecipe)
620 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
621 checkvars = {}
622 checkvars['S'] = None
623 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
624 self._test_recipe_contents(recipefile, checkvars, [])
625
Andrew Geissler82c905d2020-04-13 13:39:40 -0500626 def test_devtool_add_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600627 collections = get_bb_var('BBFILE_COLLECTIONS').split()
628 if "openembedded-layer" not in collections:
629 self.skipTest("Test needs meta-oe for nodejs")
630
Andrew Geissler82c905d2020-04-13 13:39:40 -0500631 pn = 'savoirfairelinux-node-server-example'
632 pv = '1.0.0'
633 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
634 # Test devtool add
635 self.track_for_cleanup(self.workspacedir)
636 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
637 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
638 result = runCmd('devtool add \'%s\'' % url)
639 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
640 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
641 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
642 # Test devtool status
643 result = runCmd('devtool status')
644 self.assertIn(pn, result.output)
645 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
646 bitbake('%s -c cleansstate' % pn)
647 # Test devtool build
648 result = runCmd('devtool build %s' % pn)
649
Andrew Geissler615f2f12022-07-15 14:00:58 -0500650 def test_devtool_add_python_egg_requires(self):
651 # Fetch source
652 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
653 self.track_for_cleanup(tempdir)
654 testver = '0.14.0'
655 url = 'https://files.pythonhosted.org/packages/e9/9e/25d59f5043cf763833b2581c8027fa92342c4cf8ee523b498ecdf460c16d/uvicorn-%s.tar.gz' % testver
656 testrecipe = 'python3-uvicorn'
657 srcdir = os.path.join(tempdir, testrecipe)
658 # Test devtool add
659 self.track_for_cleanup(self.workspacedir)
660 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
661 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
662
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800663class DevtoolModifyTests(DevtoolBase):
664
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500665 def test_devtool_modify(self):
666 import oe.path
667
668 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
669 self.track_for_cleanup(tempdir)
670 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500671 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400672 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500673 result = runCmd('devtool modify mdadm -x %s' % tempdir)
674 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
675 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
676 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
677 self.assertTrue(matches, 'bbappend not created %s' % result.output)
678
679 # Test devtool status
680 result = runCmd('devtool status')
681 self.assertIn('mdadm', result.output)
682 self.assertIn(tempdir, result.output)
683 self._check_src_repo(tempdir)
684
685 bitbake('mdadm -C unpack')
686
687 def check_line(checkfile, expected, message, present=True):
688 # Check for $expected, on a line on its own, in checkfile.
689 with open(checkfile, 'r') as f:
690 if present:
691 self.assertIn(expected + '\n', f, message)
692 else:
693 self.assertNotIn(expected + '\n', f, message)
694
695 modfile = os.path.join(tempdir, 'mdadm.8.in')
696 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
697 pkgd = bb_vars['PKGD']
698 self.assertTrue(pkgd, 'Could not query PKGD variable')
699 mandir = bb_vars['mandir']
700 self.assertTrue(mandir, 'Could not query mandir variable')
701 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
702
703 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
704 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
705
706 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
707 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
708
709 bitbake('mdadm -c package')
710 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
711
712 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
713 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
714
715 bitbake('mdadm -c package')
716 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
717
718 result = runCmd('devtool reset mdadm')
719 result = runCmd('devtool status')
720 self.assertNotIn('mdadm', result.output)
721
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500722 def test_devtool_buildclean(self):
723 def assertFile(path, *paths):
724 f = os.path.join(path, *paths)
725 self.assertExists(f)
726 def assertNoFile(path, *paths):
727 f = os.path.join(path, *paths)
728 self.assertNotExists(f)
729
730 # Clean up anything in the workdir/sysroot/sstate cache
731 bitbake('mdadm m4 -c cleansstate')
732 # Try modifying a recipe
733 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
734 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
735 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
736 self.track_for_cleanup(tempdir_mdadm)
737 self.track_for_cleanup(tempdir_m4)
738 self.track_for_cleanup(builddir_m4)
739 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500740 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400741 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500742 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
743 try:
744 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
745 runCmd('devtool modify m4 -x %s' % tempdir_m4)
746 assertNoFile(tempdir_mdadm, 'mdadm')
747 assertNoFile(builddir_m4, 'src/m4')
748 result = bitbake('m4 -e')
749 result = bitbake('mdadm m4 -c compile')
750 self.assertEqual(result.status, 0)
751 assertFile(tempdir_mdadm, 'mdadm')
752 assertFile(builddir_m4, 'src/m4')
753 # Check that buildclean task exists and does call make clean
754 bitbake('mdadm m4 -c buildclean')
755 assertNoFile(tempdir_mdadm, 'mdadm')
756 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400757 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500758 bitbake('mdadm m4 -c compile')
759 assertFile(tempdir_mdadm, 'mdadm')
760 assertFile(builddir_m4, 'src/m4')
761 bitbake('mdadm m4 -c clean')
762 # Check that buildclean task is run before clean for B == S
763 assertNoFile(tempdir_mdadm, 'mdadm')
764 # Check that buildclean task is not run before clean for B != S
765 assertFile(builddir_m4, 'src/m4')
766 finally:
767 self.delete_recipeinc('m4')
768
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500769 def test_devtool_modify_invalid(self):
770 # Try modifying some recipes
771 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
772 self.track_for_cleanup(tempdir)
773 self.track_for_cleanup(self.workspacedir)
774 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
775
Andrew Geissler5199d832021-09-24 16:47:35 -0500776 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500777 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
778 result = runCmd('bitbake-layers show-recipes gcc-source*')
779 for line in result.output.splitlines():
780 # just match those lines that contain a real target
781 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
782 if m:
783 testrecipes.append(m.group('recipe'))
784 for testrecipe in testrecipes:
785 # Check it's a valid recipe
786 bitbake('%s -e' % testrecipe)
787 # devtool extract should fail
788 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
789 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
790 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
791 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
792 # devtool modify should fail
793 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
794 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
795 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
796
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500797 def test_devtool_modify_native(self):
798 # Check preconditions
799 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
800 # Try modifying some recipes
801 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
802 self.track_for_cleanup(tempdir)
803 self.track_for_cleanup(self.workspacedir)
804 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
805
806 bbclassextended = False
807 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500808 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500809 for testrecipe in testrecipes:
810 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
811 if not bbclassextended:
812 bbclassextended = checkextend
813 if not inheritnative:
814 inheritnative = not checkextend
815 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
816 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
817 result = runCmd('devtool build %s' % testrecipe)
818 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
819 result = runCmd('devtool reset %s' % testrecipe)
820 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
821
822 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
823 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 -0500824
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600825 def test_devtool_modify_localfiles_only(self):
826 # Check preconditions
827 testrecipe = 'base-files'
828 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
829 foundlocalonly = False
830 correct_symlink = False
831 for item in src_uri:
832 if item.startswith('file://'):
833 if '.patch' not in item:
834 foundlocalonly = True
835 else:
836 foundlocalonly = False
837 break
838 self.assertTrue(foundlocalonly, 'This test expects the %s recipe to fetch local files only and it seems that it no longer does' % testrecipe)
839 # Clean up anything in the workdir/sysroot/sstate cache
840 bitbake('%s -c cleansstate' % testrecipe)
841 # Try modifying a recipe
842 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
843 self.track_for_cleanup(tempdir)
844 self.track_for_cleanup(self.workspacedir)
845 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
846 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
847 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
848 srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
849 srclink = os.path.join(tempdir, 'share/dot.bashrc')
850 self.assertExists(srcfile, 'Extracted source could not be found')
851 if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
852 correct_symlink = True
853 self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500854
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600855 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
856 self.assertTrue(matches, 'bbappend not created')
857 # Test devtool status
858 result = runCmd('devtool status')
859 self.assertIn(testrecipe, result.output)
860 self.assertIn(tempdir, result.output)
861 # Try building
862 bitbake(testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500863
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500864 def test_devtool_modify_git(self):
865 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400866 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500867 src_uri = get_bb_var('SRC_URI', testrecipe)
868 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
869 # Clean up anything in the workdir/sysroot/sstate cache
870 bitbake('%s -c cleansstate' % testrecipe)
871 # Try modifying a recipe
872 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
873 self.track_for_cleanup(tempdir)
874 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500875 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400876 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500877 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400878 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500879 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 -0400880 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500881 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 # Check git repo
887 self._check_src_repo(tempdir)
888 # Try building
889 bitbake(testrecipe)
890
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500891 def test_devtool_modify_git_crates_subpath(self):
892 # This tests two things in devtool context:
893 # - that we support local git dependencies for cargo based recipe
894 # - that we support patches in SRC_URI when git url contains subpath parameter
895
896 # Check preconditions:
897 # recipe inherits cargo
898 # git:// uri with a subpath as the main package
899 # some crate:// in SRC_URI
900 # others git:// in SRC_URI
901 # cointains a patch
902 testrecipe = 'zvariant'
903 bb_vars = get_bb_vars(['SRC_URI', 'FILE', 'WORKDIR', 'CARGO_HOME'], testrecipe)
904 recipefile = bb_vars['FILE']
905 workdir = bb_vars['WORKDIR']
906 cargo_home = bb_vars['CARGO_HOME']
907 src_uri = bb_vars['SRC_URI'].split()
908 self.assertTrue(src_uri[0].startswith('git://'),
909 'This test expects the %s recipe to have a git repo has its main uri' % testrecipe)
910 self.assertIn(';subpath=', src_uri[0],
911 'This test expects the %s recipe to have a git uri with subpath' % testrecipe)
912 self.assertTrue(any([uri.startswith('crate://') for uri in src_uri]),
913 'This test expects the %s recipe to have some crates in its src uris' % testrecipe)
914 self.assertGreater(sum(map(lambda x:x.startswith('git://'), src_uri)), 2,
915 'This test expects the %s recipe to have several git:// uris' % testrecipe)
916 self.assertTrue(any([uri.startswith('file://') and '.patch' in uri for uri in src_uri]),
917 'This test expects the %s recipe to have a patch in its src uris' % testrecipe)
918
Andrew Geissler028142b2023-05-05 11:29:21 -0500919 self._test_recipe_contents(recipefile, {}, ['ptest-cargo'])
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500920
921 # Clean up anything in the workdir/sysroot/sstate cache
922 bitbake('%s -c cleansstate' % testrecipe)
923 # Try modifying a recipe
924 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
925 self.track_for_cleanup(tempdir)
926 self.track_for_cleanup(self.workspacedir)
927 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
928 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
929 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
930 self.assertExists(os.path.join(tempdir, 'Cargo.toml'), 'Extracted source could not be found')
931 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
932 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'zvariant_*.bbappend'))
933 self.assertTrue(matches, 'bbappend not created')
934 # Test devtool status
935 result = runCmd('devtool status')
936 self.assertIn(testrecipe, result.output)
937 self.assertIn(tempdir, result.output)
938 # Check git repo
939 self._check_src_repo(tempdir)
940 # Check that the patch is correctly applied
941 # last commit message in the tree must contain
942 # %% original patch: <patchname>
943 # ..
944 patchname = None
945 for uri in src_uri:
946 if uri.startswith('file://') and '.patch' in uri:
947 patchname = uri.replace("file://", "").partition('.patch')[0] + '.patch'
948 self.assertIsNotNone(patchname)
949 result = runCmd('git -C %s log -1' % tempdir)
950 self.assertIn("%%%% original patch: %s" % patchname, result.output)
951
952 # Configure the recipe to check that the git dependencies are correctly patched in cargo config
953 bitbake('-c configure %s' % testrecipe)
954
955 cargo_config_path = os.path.join(cargo_home, 'config')
956 with open(cargo_config_path, "r") as f:
957 cargo_config_contents = [line.strip('\n') for line in f.readlines()]
958
959 # Get back git dependencies of the recipe (ignoring the main one)
960 # and check that they are all correctly patched to be fetched locally
961 git_deps = [uri for uri in src_uri if uri.startswith("git://")][1:]
962 for git_dep in git_deps:
963 raw_url, _, raw_parms = git_dep.partition(";")
964 parms = {}
965 for parm in raw_parms.split(";"):
966 name_parm, _, value_parm = parm.partition('=')
967 parms[name_parm]=value_parm
968 self.assertIn('protocol', parms, 'git dependencies uri should contain the "protocol" parameter')
969 self.assertIn('name', parms, 'git dependencies uri should contain the "name" parameter')
970 self.assertIn('destsuffix', parms, 'git dependencies uri should contain the "destsuffix" parameter')
971 self.assertIn('type', parms, 'git dependencies uri should contain the "type" parameter')
972 self.assertEqual(parms['type'], 'git-dependency', 'git dependencies uri should have "type=git-dependency"')
973 raw_url = raw_url.replace("git://", '%s://' % parms['protocol'])
974 patch_line = '[patch."%s"]' % raw_url
975 path_patched = os.path.join(workdir, parms['destsuffix'])
976 path_override_line = '%s = { path = "%s" }' % (parms['name'], path_patched)
977 # Would have been better to use tomllib to read this file :/
978 self.assertIn(patch_line, cargo_config_contents)
979 self.assertIn(path_override_line, cargo_config_contents)
980
981 # Try to package the recipe
982 bitbake('-c package_qa %s' % testrecipe)
983
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500984 def test_devtool_modify_localfiles(self):
985 # Check preconditions
986 testrecipe = 'lighttpd'
987 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
988 foundlocal = False
989 for item in src_uri:
990 if item.startswith('file://') and '.patch' not in item:
991 foundlocal = True
992 break
993 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
994 # Clean up anything in the workdir/sysroot/sstate cache
995 bitbake('%s -c cleansstate' % testrecipe)
996 # Try modifying a recipe
997 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
998 self.track_for_cleanup(tempdir)
999 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001000 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001001 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001002 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1003 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
1004 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
1005 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
1006 self.assertTrue(matches, 'bbappend not created')
1007 # Test devtool status
1008 result = runCmd('devtool status')
1009 self.assertIn(testrecipe, result.output)
1010 self.assertIn(tempdir, result.output)
1011 # Try building
1012 bitbake(testrecipe)
1013
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001014 def test_devtool_modify_virtual(self):
1015 # Try modifying a virtual recipe
1016 virtrecipe = 'virtual/make'
1017 realrecipe = 'make'
1018 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1019 self.track_for_cleanup(tempdir)
1020 self.track_for_cleanup(self.workspacedir)
1021 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1022 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
1023 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1024 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
1025 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
1026 self.assertTrue(matches, 'bbappend not created %s' % result.output)
1027 # Test devtool status
1028 result = runCmd('devtool status')
1029 self.assertNotIn(virtrecipe, result.output)
1030 self.assertIn(realrecipe, result.output)
1031 # Check git repo
1032 self._check_src_repo(tempdir)
1033 # This is probably sufficient
1034
Andrew Geisslerf0343792020-11-18 10:42:21 -06001035 def test_devtool_modify_overrides(self):
1036 # Try modifying a recipe with patches in overrides
1037 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1038 self.track_for_cleanup(tempdir)
1039 self.track_for_cleanup(self.workspacedir)
1040 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1041 result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
1042
1043 self._check_src_repo(tempdir)
1044 source = os.path.join(tempdir, "source")
1045 def check(branch, expected):
1046 runCmd('git -C %s checkout %s' % (tempdir, branch))
1047 with open(source, "rt") as f:
1048 content = f.read()
1049 self.assertEquals(content, expected)
1050 check('devtool', 'This is a test for something\n')
1051 check('devtool-no-overrides', 'This is a test for something\n')
1052 check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
1053 check('devtool-override-qemux86', 'This is a test for qemux86\n')
1054
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001055class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001056
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001057 def test_devtool_update_recipe(self):
1058 # Check preconditions
1059 testrecipe = 'minicom'
1060 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1061 recipefile = bb_vars['FILE']
1062 src_uri = bb_vars['SRC_URI']
1063 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1064 self._check_repo_status(os.path.dirname(recipefile), [])
1065 # First, modify a recipe
1066 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1067 self.track_for_cleanup(tempdir)
1068 self.track_for_cleanup(self.workspacedir)
1069 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1070 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1071 # We don't use -x here so that we test the behaviour of devtool modify without it
1072 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
1073 # Check git repo
1074 self._check_src_repo(tempdir)
1075 # Add a couple of commits
1076 # FIXME: this only tests adding, need to also test update and remove
1077 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
1078 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
1079 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1080 result = runCmd('git add devtool-new-file', cwd=tempdir)
1081 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1082 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1083 result = runCmd('devtool update-recipe %s' % testrecipe)
1084 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1085 ('??', '.*/0001-Change-the-README.patch$'),
1086 ('??', '.*/0002-Add-a-new-file.patch$')]
1087 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1088
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001089 def test_devtool_update_recipe_git(self):
1090 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001091 testrecipe = 'mtd-utils-selftest'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001092 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1093 recipefile = bb_vars['FILE']
1094 src_uri = bb_vars['SRC_URI']
1095 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1096 patches = []
1097 for entry in src_uri.split():
1098 if entry.startswith('file://') and entry.endswith('.patch'):
1099 patches.append(entry[7:].split(';')[0])
1100 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
1101 self._check_repo_status(os.path.dirname(recipefile), [])
1102 # First, modify a recipe
1103 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1104 self.track_for_cleanup(tempdir)
1105 self.track_for_cleanup(self.workspacedir)
1106 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1107 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1108 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1109 # Check git repo
1110 self._check_src_repo(tempdir)
1111 # Add a couple of commits
1112 # FIXME: this only tests adding, need to also test update and remove
1113 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
1114 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
1115 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1116 result = runCmd('git add devtool-new-file', cwd=tempdir)
1117 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1118 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1119 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
1120 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
1121 [(' D', '.*/%s$' % patch) for patch in patches]
1122 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1123
1124 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +00001125 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001126 srcurilines = src_uri.split()
1127 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
1128 srcurilines.append('"')
1129 removelines = ['SRCREV = ".*"'] + srcurilines
Andrew Geissler615f2f12022-07-15 14:00:58 -05001130 self._check_diff(result.output, addlines, removelines)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001131 # Now try with auto mode
1132 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
1133 result = runCmd('devtool update-recipe %s' % testrecipe)
1134 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
1135 topleveldir = result.output.strip()
1136 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
1137 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
1138 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
1139 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
1140 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1141
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001142 def test_devtool_update_recipe_append(self):
1143 # Check preconditions
1144 testrecipe = 'mdadm'
1145 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1146 recipefile = bb_vars['FILE']
1147 src_uri = bb_vars['SRC_URI']
1148 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1149 self._check_repo_status(os.path.dirname(recipefile), [])
1150 # First, modify a recipe
1151 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1152 tempsrcdir = os.path.join(tempdir, 'source')
1153 templayerdir = os.path.join(tempdir, 'layer')
1154 self.track_for_cleanup(tempdir)
1155 self.track_for_cleanup(self.workspacedir)
1156 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1157 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1158 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1159 # Check git repo
1160 self._check_src_repo(tempsrcdir)
1161 # Add a commit
1162 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
1163 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1164 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1165 # Create a temporary layer and add it to bblayers.conf
1166 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
1167 # Create the bbappend
1168 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1169 self.assertNotIn('WARNING:', result.output)
1170 # Check recipe is still clean
1171 self._check_repo_status(os.path.dirname(recipefile), [])
1172 # Check bbappend was created
1173 splitpath = os.path.dirname(recipefile).split(os.sep)
1174 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1175 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1176 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
1177 self.assertExists(patchfile, 'Patch file not created')
1178
1179 # Check bbappend contents
Patrick Williams213cb262021-08-07 19:21:33 -05001180 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001181 '\n',
1182 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
1183 '\n']
1184 with open(bbappendfile, 'r') as f:
1185 self.assertEqual(expectedlines, f.readlines())
1186
1187 # Check we can run it again and bbappend isn't modified
1188 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1189 with open(bbappendfile, 'r') as f:
1190 self.assertEqual(expectedlines, f.readlines())
1191 # Drop new commit and check patch gets deleted
1192 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1193 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1194 self.assertNotExists(patchfile, 'Patch file not deleted')
Patrick Williams213cb262021-08-07 19:21:33 -05001195 expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001196 '\n']
1197 with open(bbappendfile, 'r') as f:
1198 self.assertEqual(expectedlines2, f.readlines())
1199 # Put commit back and check we can run it if layer isn't in bblayers.conf
1200 os.remove(bbappendfile)
1201 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1202 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1203 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1204 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1205 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
1206 with open(bbappendfile, 'r') as f:
1207 self.assertEqual(expectedlines, f.readlines())
1208 # Deleting isn't expected to work under these circumstances
1209
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001210 def test_devtool_update_recipe_append_git(self):
1211 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001212 testrecipe = 'mtd-utils-selftest'
Andrew Geissler517393d2023-01-13 08:55:19 -06001213 bb_vars = get_bb_vars(['FILE', 'SRC_URI', 'LAYERSERIES_CORENAMES'], testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001214 recipefile = bb_vars['FILE']
1215 src_uri = bb_vars['SRC_URI']
Andrew Geissler517393d2023-01-13 08:55:19 -06001216 corenames = bb_vars['LAYERSERIES_CORENAMES']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001217 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1218 for entry in src_uri.split():
1219 if entry.startswith('git://'):
1220 git_uri = entry
1221 break
1222 self._check_repo_status(os.path.dirname(recipefile), [])
1223 # First, modify a recipe
1224 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1225 tempsrcdir = os.path.join(tempdir, 'source')
1226 templayerdir = os.path.join(tempdir, 'layer')
1227 self.track_for_cleanup(tempdir)
1228 self.track_for_cleanup(self.workspacedir)
1229 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1230 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1231 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1232 # Check git repo
1233 self._check_src_repo(tempsrcdir)
1234 # Add a commit
1235 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
1236 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1237 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1238 # Create a temporary layer
1239 os.makedirs(os.path.join(templayerdir, 'conf'))
1240 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
1241 f.write('BBPATH .= ":${LAYERDIR}"\n')
1242 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
1243 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
1244 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
1245 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
1246 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Andrew Geissler517393d2023-01-13 08:55:19 -06001247 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "%s"\n' % corenames)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001248 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
1249 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
1250 # Create the bbappend
1251 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1252 self.assertNotIn('WARNING:', result.output)
1253 # Check recipe is still clean
1254 self._check_repo_status(os.path.dirname(recipefile), [])
1255 # Check bbappend was created
1256 splitpath = os.path.dirname(recipefile).split(os.sep)
1257 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1258 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1259 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1260
1261 # Check bbappend contents
1262 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1263 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1264 '\n',
1265 'SRC_URI = "%s"\n' % git_uri,
1266 '\n'])
1267 with open(bbappendfile, 'r') as f:
1268 self.assertEqual(expectedlines, set(f.readlines()))
1269
1270 # Check we can run it again and bbappend isn't modified
1271 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1272 with open(bbappendfile, 'r') as f:
1273 self.assertEqual(expectedlines, set(f.readlines()))
1274 # Drop new commit and check SRCREV changes
1275 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1276 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1277 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1278 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1279 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1280 '\n',
1281 'SRC_URI = "%s"\n' % git_uri,
1282 '\n'])
1283 with open(bbappendfile, 'r') as f:
1284 self.assertEqual(expectedlines, set(f.readlines()))
1285 # Put commit back and check we can run it if layer isn't in bblayers.conf
1286 os.remove(bbappendfile)
1287 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1288 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1289 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1290 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1291 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1292 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1293 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1294 '\n',
1295 'SRC_URI = "%s"\n' % git_uri,
1296 '\n'])
1297 with open(bbappendfile, 'r') as f:
1298 self.assertEqual(expectedlines, set(f.readlines()))
1299 # Deleting isn't expected to work under these circumstances
1300
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001301 def test_devtool_update_recipe_local_files(self):
1302 """Check that local source files are copied over instead of patched"""
1303 testrecipe = 'makedevs'
1304 recipefile = get_bb_var('FILE', testrecipe)
1305 # Setup srctree for modifying the recipe
1306 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1307 self.track_for_cleanup(tempdir)
1308 self.track_for_cleanup(self.workspacedir)
1309 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1310 # (don't bother with cleaning the recipe on teardown, we won't be
1311 # building it)
1312 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1313 # Check git repo
1314 self._check_src_repo(tempdir)
1315 # Try building just to ensure we haven't broken that
1316 bitbake("%s" % testrecipe)
1317 # Edit / commit local source
1318 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1319 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1320 runCmd('echo "Bar" > new-file', cwd=tempdir)
1321 runCmd('git add new-file', cwd=tempdir)
1322 runCmd('git commit -m "Add new file"', cwd=tempdir)
1323 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1324 os.path.dirname(recipefile))
1325 runCmd('devtool update-recipe %s' % testrecipe)
1326 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1327 (' M', '.*/makedevs/makedevs.c$'),
1328 ('??', '.*/makedevs/new-local$'),
1329 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1330 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1331
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001332 def test_devtool_update_recipe_local_files_2(self):
1333 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001334 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001335 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001336 recipedir = os.path.dirname(recipefile)
1337 result = runCmd('git status --porcelain .', cwd=recipedir)
1338 if result.output.strip():
1339 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001340 # Setup srctree for modifying the recipe
1341 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1342 self.track_for_cleanup(tempdir)
1343 self.track_for_cleanup(self.workspacedir)
1344 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1345 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1346 # Check git repo
1347 self._check_src_repo(tempdir)
1348 # Add oe-local-files to Git
1349 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1350 runCmd('git add oe-local-files', cwd=tempdir)
1351 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1352 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001353 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001354 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001355 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001356 runCmd('git commit -m"Remove file"', cwd=tempdir)
1357 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1358 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1359 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1360 runCmd('echo "Gar" > new-file', cwd=tempdir)
1361 runCmd('git add new-file', cwd=tempdir)
1362 runCmd('git commit -m "Add new file"', cwd=tempdir)
1363 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1364 os.path.dirname(recipefile))
1365 # Checkout unmodified file to working copy -> devtool should still pick
1366 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001367 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001368 runCmd('devtool update-recipe %s' % testrecipe)
1369 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001370 (' M', '.*/file1$'),
1371 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001372 ('??', '.*/new-local$'),
1373 ('??', '.*/0001-Add-new-file.patch$')]
1374 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1375
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001376 def test_devtool_update_recipe_with_gitignore(self):
1377 # First, modify the recipe
1378 testrecipe = 'devtool-test-ignored'
1379 bb_vars = get_bb_vars(['FILE'], testrecipe)
1380 recipefile = bb_vars['FILE']
1381 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1382 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
1383 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1384 self.track_for_cleanup(tempdir)
1385 self.track_for_cleanup(self.workspacedir)
1386 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1387 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1388 result = runCmd('devtool modify %s' % testrecipe)
1389 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1390 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1391 # Check recipe got changed as expected
1392 with open(newpatchfile, 'r') as f:
1393 desiredlines = f.readlines()
1394 with open(patchfile, 'r') as f:
1395 newlines = f.readlines()
1396 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1397 # which changes the metadata subject which is added into the patch, but keep
1398 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1399 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1400 self.assertEqual(desiredlines[5:], newlines[5:])
1401
1402 def test_devtool_update_recipe_long_filename(self):
1403 # First, modify the recipe
1404 testrecipe = 'devtool-test-long-filename'
1405 bb_vars = get_bb_vars(['FILE'], testrecipe)
1406 recipefile = bb_vars['FILE']
1407 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1408 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1409 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1410 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1411 self.track_for_cleanup(tempdir)
1412 self.track_for_cleanup(self.workspacedir)
1413 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1414 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1415 result = runCmd('devtool modify %s' % testrecipe)
1416 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1417 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1418 # Check recipe got changed as expected
1419 with open(newpatchfile, 'r') as f:
1420 desiredlines = f.readlines()
1421 with open(patchfile, 'r') as f:
1422 newlines = f.readlines()
1423 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1424 # which changes the metadata subject which is added into the patch, but keep
1425 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1426 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1427 self.assertEqual(desiredlines[5:], newlines[5:])
1428
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001429 def test_devtool_update_recipe_local_files_3(self):
1430 # First, modify the recipe
1431 testrecipe = 'devtool-test-localonly'
1432 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1433 recipefile = bb_vars['FILE']
1434 src_uri = bb_vars['SRC_URI']
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 # Modify one file
1442 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1443 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1444 result = runCmd('devtool update-recipe %s' % testrecipe)
1445 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1446 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1447
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001448 def test_devtool_update_recipe_local_patch_gz(self):
1449 # First, modify the recipe
1450 testrecipe = 'devtool-test-patch-gz'
1451 if get_bb_var('DISTRO') == 'poky-tiny':
1452 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1453 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1454 recipefile = bb_vars['FILE']
1455 src_uri = bb_vars['SRC_URI']
1456 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1457 self.track_for_cleanup(tempdir)
1458 self.track_for_cleanup(self.workspacedir)
1459 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1460 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1461 result = runCmd('devtool modify %s' % testrecipe)
1462 # Modify one file
1463 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1464 runCmd('echo "Another line" >> README', cwd=srctree)
1465 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1466 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1467 result = runCmd('devtool update-recipe %s' % testrecipe)
1468 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1469 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1470 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1471 result = runCmd('file %s' % patch_gz)
1472 if 'gzip compressed data' not in result.output:
1473 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1474
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001475 def test_devtool_update_recipe_local_files_subdir(self):
1476 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1477 # SRC_URI such that it overwrites a file that was in an archive that
1478 # was also in SRC_URI
1479 # First, modify the recipe
1480 testrecipe = 'devtool-test-subdir'
1481 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1482 recipefile = bb_vars['FILE']
1483 src_uri = bb_vars['SRC_URI']
1484 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1485 self.track_for_cleanup(tempdir)
1486 self.track_for_cleanup(self.workspacedir)
1487 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1488 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1489 result = runCmd('devtool modify %s' % testrecipe)
1490 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1491 self.assertExists(testfile, 'Extracted source could not be found')
1492 with open(testfile, 'r') as f:
1493 contents = f.read().rstrip()
1494 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1495 # Test devtool update-recipe without modifying any files
1496 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1497 result = runCmd('devtool update-recipe %s' % testrecipe)
1498 expected_status = []
1499 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1500
Andrew Geissler615f2f12022-07-15 14:00:58 -05001501 def test_devtool_finish_modify_git_subdir(self):
1502 # Check preconditions
1503 testrecipe = 'dos2unix'
Patrick Williams520786c2023-06-25 16:20:36 -05001504 self.append_config('ERROR_QA:remove:pn-dos2unix = "patch-status"\n')
Andrew Geissler615f2f12022-07-15 14:00:58 -05001505 bb_vars = get_bb_vars(['SRC_URI', 'S', 'WORKDIR', 'FILE'], testrecipe)
1506 self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe)
1507 workdir_git = '%s/git/' % bb_vars['WORKDIR']
1508 if not bb_vars['S'].startswith(workdir_git):
1509 self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe)
1510 subdir = bb_vars['S'].split(workdir_git, 1)[1]
1511 # Clean up anything in the workdir/sysroot/sstate cache
1512 bitbake('%s -c cleansstate' % testrecipe)
1513 # Try modifying a recipe
1514 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1515 self.track_for_cleanup(tempdir)
1516 self.track_for_cleanup(self.workspacedir)
1517 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1518 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1519 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1520 testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c')
1521 self.assertExists(testsrcfile, 'Extracted source could not be found')
1522 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
1523 self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo')
1524 # Check git repo
1525 self._check_src_repo(tempdir)
1526 # Modify file
1527 runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile)
1528 result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir)
1529 # Now try updating original recipe
1530 recipefile = bb_vars['FILE']
1531 recipedir = os.path.dirname(recipefile)
1532 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1533 result = runCmd('devtool update-recipe %s' % testrecipe)
1534 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1535 ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))]
1536 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1537 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
1538 removelines = ['SRC_URI = "git://.*"']
1539 addlines = [
1540 'SRC_URI = "git://.* \\\\',
1541 'file://0001-Add-a-comment.patch;patchdir=.. \\\\',
1542 '"'
1543 ]
1544 self._check_diff(result.output, addlines, removelines)
1545 # Put things back so we can run devtool finish on a different layer
1546 runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1547 # Run devtool finish
1548 res = re.search('recipes-.*', recipedir)
1549 self.assertTrue(res, 'Unable to find recipe subdirectory')
1550 recipesubdir = res[0]
1551 self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir))
1552 result = runCmd('devtool finish %s meta-selftest' % testrecipe)
1553 # Check bbappend file contents
1554 appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe)
1555 with open(appendfn, 'r') as f:
1556 appendlines = f.readlines()
1557 expected_appendlines = [
1558 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
1559 '\n',
1560 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n',
1561 '\n'
1562 ]
1563 self.assertEqual(appendlines, expected_appendlines)
1564 self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch'))
1565 # Try building
1566 bitbake('%s -c patch' % testrecipe)
1567
1568
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001569class DevtoolExtractTests(DevtoolBase):
1570
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001571 def test_devtool_extract(self):
1572 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1573 # Try devtool extract
1574 self.track_for_cleanup(tempdir)
1575 self.track_for_cleanup(self.workspacedir)
1576 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1577 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1578 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1579 self._check_src_repo(tempdir)
1580
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001581 def test_devtool_extract_virtual(self):
1582 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1583 # Try devtool extract
1584 self.track_for_cleanup(tempdir)
1585 self.track_for_cleanup(self.workspacedir)
1586 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1587 result = runCmd('devtool extract virtual/make %s' % tempdir)
1588 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1589 self._check_src_repo(tempdir)
1590
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001591 def test_devtool_reset_all(self):
1592 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1593 self.track_for_cleanup(tempdir)
1594 self.track_for_cleanup(self.workspacedir)
1595 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1596 testrecipe1 = 'mdadm'
1597 testrecipe2 = 'cronie'
1598 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1599 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1600 result = runCmd('devtool build %s' % testrecipe1)
1601 result = runCmd('devtool build %s' % testrecipe2)
1602 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1603 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1604 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1605 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1606 result = runCmd('devtool reset -a')
1607 self.assertIn(testrecipe1, result.output)
1608 self.assertIn(testrecipe2, result.output)
1609 result = runCmd('devtool status')
1610 self.assertNotIn(testrecipe1, result.output)
1611 self.assertNotIn(testrecipe2, result.output)
1612 matches1 = glob.glob(stampprefix1 + '*')
1613 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1614 matches2 = glob.glob(stampprefix2 + '*')
1615 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1616
Patrick Williams45852732022-04-02 08:58:32 -05001617 @OETestTag("runqemu")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001618 def test_devtool_deploy_target(self):
1619 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1620 # unfortunately the runtime tests run under bitbake and you can't run
1621 # devtool within bitbake (since devtool needs to run bitbake itself).
1622 # Additionally we are testing build-time functionality as well, so
1623 # really this has to be done as an oe-selftest test.
1624 #
1625 # Check preconditions
1626 machine = get_bb_var('MACHINE')
1627 if not machine.startswith('qemu'):
1628 self.skipTest('This test only works with qemu machines')
1629 if not os.path.exists('/etc/runqemu-nosudo'):
1630 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1631 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1632 if result.status != 0:
1633 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1634 if result.status != 0:
1635 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1636 for line in result.output.splitlines():
1637 if line.startswith('tap'):
1638 break
1639 else:
1640 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1641 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1642 # Definitions
1643 testrecipe = 'mdadm'
1644 testfile = '/sbin/mdadm'
1645 testimage = 'oe-selftest-image'
1646 testcommand = '/sbin/mdadm --help'
1647 # Build an image to run
1648 bitbake("%s qemu-native qemu-helper-native" % testimage)
1649 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1650 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1651 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1652 # Clean recipe so the first deploy will fail
1653 bitbake("%s -c clean" % testrecipe)
1654 # Try devtool modify
1655 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1656 self.track_for_cleanup(tempdir)
1657 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001658 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001659 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001660 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1661 # Test that deploy-target at this point fails (properly)
1662 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1663 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1664 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1665 result = runCmd('devtool build %s' % testrecipe)
1666 # First try a dry-run of deploy-target
1667 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1668 self.assertIn(' %s' % testfile, result.output)
1669 # Boot the image
1670 with runqemu(testimage) as qemu:
1671 # Now really test deploy-target
1672 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1673 # Run a test command to see if it was installed properly
1674 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1675 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1676 # Check if it deployed all of the files with the right ownership/perms
1677 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1678 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1679 installdir = bb_vars['D']
1680 fakerootenv = bb_vars['FAKEROOTENV']
1681 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001682 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001683 filelist1 = self._process_ls_output(result.output)
1684
1685 # Now look on the target
1686 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1687 self.track_for_cleanup(tempdir2)
1688 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1689 with open(tmpfilelist, 'w') as f:
1690 for line in filelist1:
1691 splitline = line.split()
1692 f.write(splitline[-1] + '\n')
1693 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1694 filelist2 = self._process_ls_output(result.output)
1695 filelist1.sort(key=lambda item: item.split()[-1])
1696 filelist2.sort(key=lambda item: item.split()[-1])
1697 self.assertEqual(filelist1, filelist2)
1698 # Test undeploy-target
1699 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1700 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1701 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1702
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001703 def test_devtool_build_image(self):
1704 """Test devtool build-image plugin"""
1705 # Check preconditions
1706 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1707 image = 'core-image-minimal'
1708 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001709 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001710 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001711 bitbake('%s -c clean' % image)
1712 # Add target and native recipes to workspace
1713 recipes = ['mdadm', 'parted-native']
1714 for recipe in recipes:
1715 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1716 self.track_for_cleanup(tempdir)
1717 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1718 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1719 # Try to build image
1720 result = runCmd('devtool build-image %s' % image)
1721 self.assertNotEqual(result, 0, 'devtool build-image failed')
1722 # Check if image contains expected packages
1723 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1724 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1725 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1726 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1727 for line in f:
1728 splitval = line.split()
1729 if splitval:
1730 pkg = splitval[0]
1731 if pkg in reqpkgs:
1732 reqpkgs.remove(pkg)
1733 if reqpkgs:
1734 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1735
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001736class DevtoolUpgradeTests(DevtoolBase):
1737
Patrick Williams45852732022-04-02 08:58:32 -05001738 def setUp(self):
1739 super().setUp()
1740 try:
1741 runCmd("git config --global user.name")
1742 runCmd("git config --global user.email")
1743 except:
1744 self.skip("Git user.name and user.email must be set")
1745
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001746 def test_devtool_upgrade(self):
1747 # Check preconditions
1748 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1749 self.track_for_cleanup(self.workspacedir)
1750 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1751 # Check parameters
1752 result = runCmd('devtool upgrade -h')
1753 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1754 self.assertIn(param, result.output)
1755 # For the moment, we are using a real recipe.
1756 recipe = 'devtool-upgrade-test1'
1757 version = '1.6.0'
1758 oldrecipefile = get_bb_var('FILE', recipe)
1759 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1760 self.track_for_cleanup(tempdir)
1761 # Check that recipe is not already under devtool control
1762 result = runCmd('devtool status')
1763 self.assertNotIn(recipe, result.output)
1764 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1765 # we are downgrading instead of upgrading.
1766 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1767 # Check if srctree at least is populated
1768 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1769 # Check new recipe subdirectory is present
1770 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1771 # Check new recipe file is present
1772 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1773 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1774 # Check devtool status and make sure recipe is present
1775 result = runCmd('devtool status')
1776 self.assertIn(recipe, result.output)
1777 self.assertIn(tempdir, result.output)
1778 # Check recipe got changed as expected
1779 with open(oldrecipefile + '.upgraded', 'r') as f:
1780 desiredlines = f.readlines()
1781 with open(newrecipefile, 'r') as f:
1782 newlines = f.readlines()
1783 self.assertEqual(desiredlines, newlines)
1784 # Check devtool reset recipe
1785 result = runCmd('devtool reset %s -n' % recipe)
1786 result = runCmd('devtool status')
1787 self.assertNotIn(recipe, result.output)
1788 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1789
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001790 def test_devtool_upgrade_git(self):
1791 # Check preconditions
1792 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1793 self.track_for_cleanup(self.workspacedir)
1794 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1795 recipe = 'devtool-upgrade-test2'
1796 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1797 oldrecipefile = get_bb_var('FILE', recipe)
1798 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1799 self.track_for_cleanup(tempdir)
1800 # Check that recipe is not already under devtool control
1801 result = runCmd('devtool status')
1802 self.assertNotIn(recipe, result.output)
1803 # Check upgrade
1804 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1805 # Check if srctree at least is populated
1806 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1807 # Check new recipe file is present
1808 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1809 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1810 # Check devtool status and make sure recipe is present
1811 result = runCmd('devtool status')
1812 self.assertIn(recipe, result.output)
1813 self.assertIn(tempdir, result.output)
1814 # Check recipe got changed as expected
1815 with open(oldrecipefile + '.upgraded', 'r') as f:
1816 desiredlines = f.readlines()
1817 with open(newrecipefile, 'r') as f:
1818 newlines = f.readlines()
1819 self.assertEqual(desiredlines, newlines)
1820 # Check devtool reset recipe
1821 result = runCmd('devtool reset %s -n' % recipe)
1822 result = runCmd('devtool status')
1823 self.assertNotIn(recipe, result.output)
1824 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1825
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001826 def test_devtool_layer_plugins(self):
1827 """Test that devtool can use plugins from other layers.
1828
1829 This test executes the selftest-reverse command from meta-selftest."""
1830
1831 self.track_for_cleanup(self.workspacedir)
1832 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1833
1834 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1835 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1836 self.assertEqual(result.output, s[::-1])
1837
1838 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1839 dstdir = basedstdir
1840 self.assertExists(dstdir)
1841 for p in paths:
1842 dstdir = os.path.join(dstdir, p)
1843 if not os.path.exists(dstdir):
1844 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001845 if p == "lib":
1846 # Can race with other tests
1847 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1848 else:
1849 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001850 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1851 if srcfile != dstfile:
1852 shutil.copy(srcfile, dstfile)
1853 self.track_for_cleanup(dstfile)
1854
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001855 def test_devtool_load_plugin(self):
1856 """Test that devtool loads only the first found plugin in BBPATH."""
1857
1858 self.track_for_cleanup(self.workspacedir)
1859 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1860
1861 devtool = runCmd("which devtool")
1862 fromname = runCmd("devtool --quiet pluginfile")
1863 srcfile = fromname.output
1864 bbpath = get_bb_var('BBPATH')
1865 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1866 plugincontent = []
1867 with open(srcfile) as fh:
1868 plugincontent = fh.readlines()
1869 try:
1870 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1871 for path in searchpath:
1872 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1873 result = runCmd("devtool --quiet count")
1874 self.assertEqual(result.output, '1')
1875 result = runCmd("devtool --quiet multiloaded")
1876 self.assertEqual(result.output, "no")
1877 for path in searchpath:
1878 result = runCmd("devtool --quiet bbdir")
1879 self.assertEqual(result.output, path)
1880 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1881 finally:
1882 with open(srcfile, 'w') as fh:
1883 fh.writelines(plugincontent)
1884
1885 def _setup_test_devtool_finish_upgrade(self):
1886 # Check preconditions
1887 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1888 self.track_for_cleanup(self.workspacedir)
1889 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1890 # Use a "real" recipe from meta-selftest
1891 recipe = 'devtool-upgrade-test1'
1892 oldversion = '1.5.3'
1893 newversion = '1.6.0'
1894 oldrecipefile = get_bb_var('FILE', recipe)
1895 recipedir = os.path.dirname(oldrecipefile)
1896 result = runCmd('git status --porcelain .', cwd=recipedir)
1897 if result.output.strip():
1898 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1899 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1900 self.track_for_cleanup(tempdir)
1901 # Check that recipe is not already under devtool control
1902 result = runCmd('devtool status')
1903 self.assertNotIn(recipe, result.output)
1904 # Do the upgrade
1905 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1906 # Check devtool status and make sure recipe is present
1907 result = runCmd('devtool status')
1908 self.assertIn(recipe, result.output)
1909 self.assertIn(tempdir, result.output)
1910 # Make a change to the source
1911 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1912 result = runCmd('git status --porcelain', cwd=tempdir)
1913 self.assertIn('M src/pv/number.c', result.output)
1914 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1915 # Check if patch is there
1916 recipedir = os.path.dirname(oldrecipefile)
1917 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1918 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001919 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001920 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001921 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1922 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001923
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001924 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001925 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001926 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1927 self.assertIn('/meta-selftest/', recipedir)
1928 # Try finish to the original layer
1929 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1930 result = runCmd('devtool finish %s meta-selftest' % recipe)
1931 result = runCmd('devtool status')
1932 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1933 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1934 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1935 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001936 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 -05001937 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1938 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1939 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1940 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 -05001941 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 -05001942 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 -05001943 with open(newrecipefile, 'r') as f:
1944 newcontent = f.read()
1945 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1946 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1947 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1948 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1949
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001950
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001951 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001952 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001953 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1954 self.assertIn('/meta-selftest/', recipedir)
1955 # Try finish to a different layer - should create a bbappend
1956 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1957 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1958 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1959 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1960 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1961 self.track_for_cleanup(newrecipedir)
1962 result = runCmd('devtool finish %s oe-core' % recipe)
1963 result = runCmd('devtool status')
1964 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1965 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1966 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1967 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001968 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001969 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1970 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1971 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 -05001972 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 -05001973 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 -05001974 with open(newrecipefile, 'r') as f:
1975 newcontent = f.read()
1976 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1977 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1978 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1979 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 -05001980
1981 def _setup_test_devtool_finish_modify(self):
1982 # Check preconditions
1983 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1984 # Try modifying a recipe
1985 self.track_for_cleanup(self.workspacedir)
1986 recipe = 'mdadm'
1987 oldrecipefile = get_bb_var('FILE', recipe)
1988 recipedir = os.path.dirname(oldrecipefile)
1989 result = runCmd('git status --porcelain .', cwd=recipedir)
1990 if result.output.strip():
1991 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1992 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1993 self.track_for_cleanup(tempdir)
1994 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1995 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1996 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1997 # Test devtool status
1998 result = runCmd('devtool status')
1999 self.assertIn(recipe, result.output)
2000 self.assertIn(tempdir, result.output)
2001 # Make a change to the source
2002 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
2003 result = runCmd('git status --porcelain', cwd=tempdir)
2004 self.assertIn('M maps.c', result.output)
2005 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
2006 for entry in os.listdir(recipedir):
2007 filesdir = os.path.join(recipedir, entry)
2008 if os.path.isdir(filesdir):
2009 break
2010 else:
2011 self.fail('Unable to find recipe files directory for %s' % recipe)
2012 return recipe, oldrecipefile, recipedir, filesdir
2013
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002014 def test_devtool_finish_modify_origlayer(self):
2015 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
2016 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
2017 self.assertIn('/meta/', recipedir)
2018 # Try finish to the original layer
2019 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2020 result = runCmd('devtool finish %s meta' % recipe)
2021 result = runCmd('devtool status')
2022 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2023 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2024 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
2025 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
2026 self._check_repo_status(recipedir, expected_status)
2027
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002028 def test_devtool_finish_modify_otherlayer(self):
2029 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
2030 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
2031 self.assertIn('/meta/', recipedir)
2032 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
2033 appenddir = os.path.join(get_test_layer(), relpth)
2034 self.track_for_cleanup(appenddir)
2035 # Try finish to the original layer
2036 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2037 result = runCmd('devtool finish %s meta-selftest' % recipe)
2038 result = runCmd('devtool status')
2039 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2040 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2041 result = runCmd('git status --porcelain .', cwd=recipedir)
2042 if result.output.strip():
2043 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
2044 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
2045 recipefn = recipefn.split('_')[0] + '_%'
2046 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
2047 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
2048 newdir = os.path.join(appenddir, recipe)
2049 files = os.listdir(newdir)
2050 foundpatch = None
2051 for fn in files:
2052 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
2053 foundpatch = fn
2054 if not foundpatch:
2055 self.fail('No patch file created next to bbappend')
2056 files.remove(foundpatch)
2057 if files:
2058 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
2059
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002060 def test_devtool_rename(self):
2061 # Check preconditions
2062 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
2063 self.track_for_cleanup(self.workspacedir)
2064 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
2065
2066 # First run devtool add
2067 # We already have this recipe in OE-Core, but that doesn't matter
2068 recipename = 'i2c-tools'
2069 recipever = '3.1.2'
2070 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
2071 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
2072 def add_recipe():
2073 result = runCmd('devtool add %s' % url)
2074 self.assertExists(recipefile, 'Expected recipe file not created')
2075 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
2076 checkvars = {}
2077 checkvars['S'] = None
2078 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2079 self._test_recipe_contents(recipefile, checkvars, [])
2080 add_recipe()
2081 # Now rename it - change both name and version
2082 newrecipename = 'mynewrecipe'
2083 newrecipever = '456'
2084 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
2085 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
2086 self.assertExists(newrecipefile, 'Recipe file not renamed')
2087 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2088 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
2089 self.assertExists(newsrctree, 'Source directory not renamed')
2090 checkvars = {}
2091 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
2092 checkvars['SRC_URI'] = url
2093 self._test_recipe_contents(newrecipefile, checkvars, [])
2094 # Try again - change just name this time
2095 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002096 add_recipe()
2097 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
2098 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
2099 self.assertExists(newrecipefile, 'Recipe file not renamed')
2100 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2101 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
2102 checkvars = {}
2103 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
2104 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2105 self._test_recipe_contents(newrecipefile, checkvars, [])
2106 # Try again - change just version this time
2107 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002108 add_recipe()
2109 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
2110 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
2111 self.assertExists(newrecipefile, 'Recipe file not renamed')
2112 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
2113 checkvars = {}
2114 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
2115 checkvars['SRC_URI'] = url
2116 self._test_recipe_contents(newrecipefile, checkvars, [])
2117
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002118 def test_devtool_virtual_kernel_modify(self):
2119 """
2120 Summary: The purpose of this test case is to verify that
2121 devtool modify works correctly when building
2122 the kernel.
2123 Dependencies: NA
2124 Steps: 1. Build kernel with bitbake.
2125 2. Save the config file generated.
2126 3. Clean the environment.
2127 4. Use `devtool modify virtual/kernel` to validate following:
2128 4.1 The source is checked out correctly.
2129 4.2 The resulting configuration is the same as
2130 what was get on step 2.
2131 4.3 The Kernel can be build correctly.
2132 4.4 Changes made on the source are reflected on the
2133 subsequent builds.
2134 4.5 Changes on the configuration are reflected on the
2135 subsequent builds
2136 Expected: devtool modify is able to checkout the source of the kernel
2137 and modification to the source and configurations are reflected
2138 when building the kernel.
Patrick Williams45852732022-04-02 08:58:32 -05002139 """
2140 kernel_provider = self.td['PREFERRED_PROVIDER_virtual/kernel']
2141
Andrew Geissler82c905d2020-04-13 13:39:40 -05002142 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002143 bitbake('%s -c clean' % kernel_provider)
2144 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2145 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
2146 self.track_for_cleanup(tempdir)
2147 self.track_for_cleanup(tempdir_cfg)
2148 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002149 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04002150 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002151 #Step 1
2152 #Here is just generated the config file instead of all the kernel to optimize the
2153 #time of executing this test case.
2154 bitbake('%s -c configure' % kernel_provider)
2155 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
2156 #Step 2
2157 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
2158 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
2159
2160 tmpconfig = os.path.join(tempdir_cfg, '.config')
2161 #Step 3
2162 bitbake('%s -c clean' % kernel_provider)
2163 #Step 4.1
2164 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
2165 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2166 #Step 4.2
2167 configfile = os.path.join(tempdir,'.config')
Patrick Williams45852732022-04-02 08:58:32 -05002168 runCmd('diff %s %s' % (tmpconfig, configfile))
2169
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002170 #Step 4.3
2171 #NOTE: virtual/kernel is mapped to kernel_provider
Patrick Williams45852732022-04-02 08:58:32 -05002172 runCmd('devtool build %s' % kernel_provider)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002173 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
2174 self.assertExists(kernelfile, 'Kernel was not build correctly')
2175
2176 #Modify the kernel source
Patrick Williams45852732022-04-02 08:58:32 -05002177 modfile = os.path.join(tempdir, 'init/version.c')
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002178 # Moved to uts.h in 6.1 onwards
2179 modfile2 = os.path.join(tempdir, 'include/linux/uts.h')
2180 runCmd("sed -i 's/Linux/LiNuX/g' %s %s" % (modfile, modfile2))
Patrick Williams45852732022-04-02 08:58:32 -05002181
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002182 #Modify the configuration
Patrick Williams45852732022-04-02 08:58:32 -05002183 codeconfigfile = os.path.join(tempdir, '.config.new')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002184 modconfopt = "CONFIG_SG_POOL=n"
Patrick Williams45852732022-04-02 08:58:32 -05002185 runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
2186
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002187 #Build again kernel with devtool
Patrick Williams45852732022-04-02 08:58:32 -05002188 runCmd('devtool build %s' % kernel_provider)
2189
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002190 #Step 4.4
Patrick Williams45852732022-04-02 08:58:32 -05002191 runCmd("grep '%s' %s" % ('LiNuX', kernelfile))
2192
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002193 #Step 4.5
Patrick Williams45852732022-04-02 08:58:32 -05002194 runCmd("grep %s %s" % (modconfopt, codeconfigfile))