blob: 397895c9367d393fc8ee9a04757e4d7df27c6ad4 [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
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500369 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800370 # We need dbus built so that DEPENDS recognition works
371 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500372 # Fetch source from a remote URL, but do it outside of devtool
373 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
374 self.track_for_cleanup(tempdir)
375 pn = 'dbus-wait'
376 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
377 # We choose an https:// git URL here to check rewriting the URL works
378 url = 'https://git.yoctoproject.org/git/dbus-wait'
379 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
380 # instead of the directory name
381 result = runCmd('git clone %s noname' % url, cwd=tempdir)
382 srcdir = os.path.join(tempdir, 'noname')
383 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
384 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
385 # Test devtool add
386 self.track_for_cleanup(self.workspacedir)
387 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
388 # Don't specify a name since we should be able to auto-detect it
389 result = runCmd('devtool add %s' % srcdir)
390 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
391 # Check the recipe name is correct
392 recipefile = get_bb_var('FILE', pn)
393 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
394 self.assertIn(recipefile, result.output)
395 # Test devtool status
396 result = runCmd('devtool status')
397 self.assertIn(pn, result.output)
398 self.assertIn(srcdir, result.output)
399 self.assertIn(recipefile, result.output)
400 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000401 checkvars['LICENSE'] = 'GPL-2.0-only'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500402 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
403 checkvars['S'] = '${WORKDIR}/git'
404 checkvars['PV'] = '0.1+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000405 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500406 checkvars['SRCREV'] = srcrev
407 checkvars['DEPENDS'] = set(['dbus'])
408 self._test_recipe_contents(recipefile, checkvars, [])
409
Patrick Williams92b42cb2022-09-03 06:53:57 -0500410 def test_devtool_add_git_style1(self):
411 version = 'v3.1.0'
412 pn = 'mbedtls'
413 # this will trigger reformat_git_uri with branch parameter in url
414 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https'"
415 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https"
416 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
417
418 def test_devtool_add_git_style2(self):
419 version = 'v3.1.0'
420 pn = 'mbedtls'
421 # this will trigger reformat_git_uri with branch parameter in url
422 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;protocol=https'"
423 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;protocol=https;branch=master"
424 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
425
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500426 def test_devtool_add_library(self):
427 # Fetch source
428 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
429 self.track_for_cleanup(tempdir)
430 version = '1.1'
431 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
432 result = runCmd('wget %s' % url, cwd=tempdir)
433 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
434 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
435 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
436 # Test devtool add (and use -V so we test that too)
437 self.track_for_cleanup(self.workspacedir)
438 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
439 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
440 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
441 # Test devtool status
442 result = runCmd('devtool status')
443 self.assertIn('libftdi', result.output)
444 self.assertIn(srcdir, result.output)
445 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
446 bitbake('libftdi -c cleansstate')
447 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
448 # There's also the matter of it installing cmake files to a path we don't
449 # normally cover, which triggers the installed-vs-shipped QA test we have
450 # within do_package
451 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
452 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
453 with open(recipefile, 'a') as f:
Patrick Williams213cb262021-08-07 19:21:33 -0500454 f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500455 # We don't have the ability to pick up this dependency automatically yet...
456 f.write('\nDEPENDS += "libusb1"\n')
457 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
458 # Test devtool build
459 result = runCmd('devtool build libftdi')
460 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
461 staging_libdir = bb_vars['TESTLIBOUTPUT']
462 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
463 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)
464 # Test devtool reset
465 stampprefix = bb_vars['STAMP']
466 result = runCmd('devtool reset libftdi')
467 result = runCmd('devtool status')
468 self.assertNotIn('libftdi', result.output)
469 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
470 matches = glob.glob(stampprefix + '*')
471 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
472 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
473
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500474 def test_devtool_add_fetch(self):
475 # Fetch source
476 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
477 self.track_for_cleanup(tempdir)
478 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400479 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500480 testrecipe = 'python-markupsafe'
481 srcdir = os.path.join(tempdir, testrecipe)
482 # Test devtool add
483 self.track_for_cleanup(self.workspacedir)
484 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
485 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
486 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
487 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
488 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
489 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
490 # Test devtool status
491 result = runCmd('devtool status')
492 self.assertIn(testrecipe, result.output)
493 self.assertIn(srcdir, result.output)
494 # Check recipe
495 recipefile = get_bb_var('FILE', testrecipe)
496 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
497 checkvars = {}
498 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
499 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
500 self._test_recipe_contents(recipefile, checkvars, [])
501 # Try with version specified
502 result = runCmd('devtool reset -n %s' % testrecipe)
503 shutil.rmtree(srcdir)
504 fakever = '1.9'
505 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
506 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
507 # Test devtool status
508 result = runCmd('devtool status')
509 self.assertIn(testrecipe, result.output)
510 self.assertIn(srcdir, result.output)
511 # Check recipe
512 recipefile = get_bb_var('FILE', testrecipe)
513 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
514 checkvars = {}
515 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
516 checkvars['SRC_URI'] = url
517 self._test_recipe_contents(recipefile, checkvars, [])
Andrew Geissler615f2f12022-07-15 14:00:58 -0500518
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500519 def test_devtool_add_fetch_git(self):
520 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
521 self.track_for_cleanup(tempdir)
522 url = 'gitsm://git.yoctoproject.org/mraa'
Andrew Geissler595f6302022-01-24 19:11:47 +0000523 url_branch = '%s;branch=master' % url
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500524 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
525 testrecipe = 'mraa'
526 srcdir = os.path.join(tempdir, testrecipe)
527 # Test devtool add
528 self.track_for_cleanup(self.workspacedir)
529 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
530 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
531 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
532 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
533 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
534 # Test devtool status
535 result = runCmd('devtool status')
536 self.assertIn(testrecipe, result.output)
537 self.assertIn(srcdir, result.output)
538 # Check recipe
539 recipefile = get_bb_var('FILE', testrecipe)
540 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
541 checkvars = {}
542 checkvars['S'] = '${WORKDIR}/git'
543 checkvars['PV'] = '1.0+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000544 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500545 checkvars['SRCREV'] = '${AUTOREV}'
546 self._test_recipe_contents(recipefile, checkvars, [])
547 # Try with revision and version specified
548 result = runCmd('devtool reset -n %s' % testrecipe)
549 shutil.rmtree(srcdir)
550 url_rev = '%s;rev=%s' % (url, checkrev)
551 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
552 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
553 # Test devtool status
554 result = runCmd('devtool status')
555 self.assertIn(testrecipe, result.output)
556 self.assertIn(srcdir, result.output)
557 # Check recipe
558 recipefile = get_bb_var('FILE', testrecipe)
559 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
560 checkvars = {}
561 checkvars['S'] = '${WORKDIR}/git'
562 checkvars['PV'] = '1.5+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000563 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500564 checkvars['SRCREV'] = checkrev
565 self._test_recipe_contents(recipefile, checkvars, [])
566
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500567 def test_devtool_add_fetch_simple(self):
568 # Fetch source from a remote URL, auto-detecting name
569 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
570 self.track_for_cleanup(tempdir)
571 testver = '1.6.0'
572 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
573 testrecipe = 'pv'
574 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
575 # Test devtool add
576 self.track_for_cleanup(self.workspacedir)
577 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
578 result = runCmd('devtool add %s' % url)
579 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
580 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
581 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
582 # Test devtool status
583 result = runCmd('devtool status')
584 self.assertIn(testrecipe, result.output)
585 self.assertIn(srcdir, result.output)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500586 # Check recipedevtool add
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500587 recipefile = get_bb_var('FILE', testrecipe)
588 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
589 checkvars = {}
590 checkvars['S'] = None
591 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
592 self._test_recipe_contents(recipefile, checkvars, [])
593
Andrew Geissler82c905d2020-04-13 13:39:40 -0500594 def test_devtool_add_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600595 collections = get_bb_var('BBFILE_COLLECTIONS').split()
596 if "openembedded-layer" not in collections:
597 self.skipTest("Test needs meta-oe for nodejs")
598
Andrew Geissler82c905d2020-04-13 13:39:40 -0500599 pn = 'savoirfairelinux-node-server-example'
600 pv = '1.0.0'
601 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
602 # Test devtool add
603 self.track_for_cleanup(self.workspacedir)
604 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
605 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
606 result = runCmd('devtool add \'%s\'' % url)
607 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
608 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
609 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
610 # Test devtool status
611 result = runCmd('devtool status')
612 self.assertIn(pn, result.output)
613 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
614 bitbake('%s -c cleansstate' % pn)
615 # Test devtool build
616 result = runCmd('devtool build %s' % pn)
617
Andrew Geissler615f2f12022-07-15 14:00:58 -0500618 def test_devtool_add_python_egg_requires(self):
619 # Fetch source
620 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
621 self.track_for_cleanup(tempdir)
622 testver = '0.14.0'
623 url = 'https://files.pythonhosted.org/packages/e9/9e/25d59f5043cf763833b2581c8027fa92342c4cf8ee523b498ecdf460c16d/uvicorn-%s.tar.gz' % testver
624 testrecipe = 'python3-uvicorn'
625 srcdir = os.path.join(tempdir, testrecipe)
626 # Test devtool add
627 self.track_for_cleanup(self.workspacedir)
628 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
629 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
630
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800631class DevtoolModifyTests(DevtoolBase):
632
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500633 def test_devtool_modify(self):
634 import oe.path
635
636 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
637 self.track_for_cleanup(tempdir)
638 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500639 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400640 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500641 result = runCmd('devtool modify mdadm -x %s' % tempdir)
642 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
643 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
644 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
645 self.assertTrue(matches, 'bbappend not created %s' % result.output)
646
647 # Test devtool status
648 result = runCmd('devtool status')
649 self.assertIn('mdadm', result.output)
650 self.assertIn(tempdir, result.output)
651 self._check_src_repo(tempdir)
652
653 bitbake('mdadm -C unpack')
654
655 def check_line(checkfile, expected, message, present=True):
656 # Check for $expected, on a line on its own, in checkfile.
657 with open(checkfile, 'r') as f:
658 if present:
659 self.assertIn(expected + '\n', f, message)
660 else:
661 self.assertNotIn(expected + '\n', f, message)
662
663 modfile = os.path.join(tempdir, 'mdadm.8.in')
664 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
665 pkgd = bb_vars['PKGD']
666 self.assertTrue(pkgd, 'Could not query PKGD variable')
667 mandir = bb_vars['mandir']
668 self.assertTrue(mandir, 'Could not query mandir variable')
669 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
670
671 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
672 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
673
674 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
675 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
676
677 bitbake('mdadm -c package')
678 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
679
680 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
681 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
682
683 bitbake('mdadm -c package')
684 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
685
686 result = runCmd('devtool reset mdadm')
687 result = runCmd('devtool status')
688 self.assertNotIn('mdadm', result.output)
689
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500690 def test_devtool_buildclean(self):
691 def assertFile(path, *paths):
692 f = os.path.join(path, *paths)
693 self.assertExists(f)
694 def assertNoFile(path, *paths):
695 f = os.path.join(path, *paths)
696 self.assertNotExists(f)
697
698 # Clean up anything in the workdir/sysroot/sstate cache
699 bitbake('mdadm m4 -c cleansstate')
700 # Try modifying a recipe
701 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
702 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
703 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
704 self.track_for_cleanup(tempdir_mdadm)
705 self.track_for_cleanup(tempdir_m4)
706 self.track_for_cleanup(builddir_m4)
707 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500708 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400709 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500710 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
711 try:
712 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
713 runCmd('devtool modify m4 -x %s' % tempdir_m4)
714 assertNoFile(tempdir_mdadm, 'mdadm')
715 assertNoFile(builddir_m4, 'src/m4')
716 result = bitbake('m4 -e')
717 result = bitbake('mdadm m4 -c compile')
718 self.assertEqual(result.status, 0)
719 assertFile(tempdir_mdadm, 'mdadm')
720 assertFile(builddir_m4, 'src/m4')
721 # Check that buildclean task exists and does call make clean
722 bitbake('mdadm m4 -c buildclean')
723 assertNoFile(tempdir_mdadm, 'mdadm')
724 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400725 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500726 bitbake('mdadm m4 -c compile')
727 assertFile(tempdir_mdadm, 'mdadm')
728 assertFile(builddir_m4, 'src/m4')
729 bitbake('mdadm m4 -c clean')
730 # Check that buildclean task is run before clean for B == S
731 assertNoFile(tempdir_mdadm, 'mdadm')
732 # Check that buildclean task is not run before clean for B != S
733 assertFile(builddir_m4, 'src/m4')
734 finally:
735 self.delete_recipeinc('m4')
736
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500737 def test_devtool_modify_invalid(self):
738 # Try modifying some recipes
739 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
740 self.track_for_cleanup(tempdir)
741 self.track_for_cleanup(self.workspacedir)
742 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
743
Andrew Geissler5199d832021-09-24 16:47:35 -0500744 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500745 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
746 result = runCmd('bitbake-layers show-recipes gcc-source*')
747 for line in result.output.splitlines():
748 # just match those lines that contain a real target
749 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
750 if m:
751 testrecipes.append(m.group('recipe'))
752 for testrecipe in testrecipes:
753 # Check it's a valid recipe
754 bitbake('%s -e' % testrecipe)
755 # devtool extract should fail
756 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
757 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
758 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
759 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
760 # devtool modify should fail
761 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
762 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
763 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
764
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500765 def test_devtool_modify_native(self):
766 # Check preconditions
767 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
768 # Try modifying some recipes
769 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
770 self.track_for_cleanup(tempdir)
771 self.track_for_cleanup(self.workspacedir)
772 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
773
774 bbclassextended = False
775 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500776 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500777 for testrecipe in testrecipes:
778 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
779 if not bbclassextended:
780 bbclassextended = checkextend
781 if not inheritnative:
782 inheritnative = not checkextend
783 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
784 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
785 result = runCmd('devtool build %s' % testrecipe)
786 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
787 result = runCmd('devtool reset %s' % testrecipe)
788 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
789
790 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
791 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 -0500792
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600793 def test_devtool_modify_localfiles_only(self):
794 # Check preconditions
795 testrecipe = 'base-files'
796 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
797 foundlocalonly = False
798 correct_symlink = False
799 for item in src_uri:
800 if item.startswith('file://'):
801 if '.patch' not in item:
802 foundlocalonly = True
803 else:
804 foundlocalonly = False
805 break
806 self.assertTrue(foundlocalonly, 'This test expects the %s recipe to fetch local files only and it seems that it no longer does' % testrecipe)
807 # Clean up anything in the workdir/sysroot/sstate cache
808 bitbake('%s -c cleansstate' % testrecipe)
809 # Try modifying a recipe
810 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
811 self.track_for_cleanup(tempdir)
812 self.track_for_cleanup(self.workspacedir)
813 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
814 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
815 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
816 srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
817 srclink = os.path.join(tempdir, 'share/dot.bashrc')
818 self.assertExists(srcfile, 'Extracted source could not be found')
819 if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
820 correct_symlink = True
821 self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500822
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600823 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
824 self.assertTrue(matches, 'bbappend not created')
825 # Test devtool status
826 result = runCmd('devtool status')
827 self.assertIn(testrecipe, result.output)
828 self.assertIn(tempdir, result.output)
829 # Try building
830 bitbake(testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500831
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500832 def test_devtool_modify_git(self):
833 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400834 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500835 src_uri = get_bb_var('SRC_URI', testrecipe)
836 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
837 # Clean up anything in the workdir/sysroot/sstate cache
838 bitbake('%s -c cleansstate' % testrecipe)
839 # Try modifying a recipe
840 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
841 self.track_for_cleanup(tempdir)
842 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500843 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400844 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500845 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400846 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500847 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 -0400848 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500849 self.assertTrue(matches, 'bbappend not created')
850 # Test devtool status
851 result = runCmd('devtool status')
852 self.assertIn(testrecipe, result.output)
853 self.assertIn(tempdir, result.output)
854 # Check git repo
855 self._check_src_repo(tempdir)
856 # Try building
857 bitbake(testrecipe)
858
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500859 def test_devtool_modify_git_crates_subpath(self):
860 # This tests two things in devtool context:
861 # - that we support local git dependencies for cargo based recipe
862 # - that we support patches in SRC_URI when git url contains subpath parameter
863
864 # Check preconditions:
865 # recipe inherits cargo
866 # git:// uri with a subpath as the main package
867 # some crate:// in SRC_URI
868 # others git:// in SRC_URI
869 # cointains a patch
870 testrecipe = 'zvariant'
871 bb_vars = get_bb_vars(['SRC_URI', 'FILE', 'WORKDIR', 'CARGO_HOME'], testrecipe)
872 recipefile = bb_vars['FILE']
873 workdir = bb_vars['WORKDIR']
874 cargo_home = bb_vars['CARGO_HOME']
875 src_uri = bb_vars['SRC_URI'].split()
876 self.assertTrue(src_uri[0].startswith('git://'),
877 'This test expects the %s recipe to have a git repo has its main uri' % testrecipe)
878 self.assertIn(';subpath=', src_uri[0],
879 'This test expects the %s recipe to have a git uri with subpath' % testrecipe)
880 self.assertTrue(any([uri.startswith('crate://') for uri in src_uri]),
881 'This test expects the %s recipe to have some crates in its src uris' % testrecipe)
882 self.assertGreater(sum(map(lambda x:x.startswith('git://'), src_uri)), 2,
883 'This test expects the %s recipe to have several git:// uris' % testrecipe)
884 self.assertTrue(any([uri.startswith('file://') and '.patch' in uri for uri in src_uri]),
885 'This test expects the %s recipe to have a patch in its src uris' % testrecipe)
886
Andrew Geissler028142b2023-05-05 11:29:21 -0500887 self._test_recipe_contents(recipefile, {}, ['ptest-cargo'])
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500888
889 # Clean up anything in the workdir/sysroot/sstate cache
890 bitbake('%s -c cleansstate' % testrecipe)
891 # Try modifying a recipe
892 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
893 self.track_for_cleanup(tempdir)
894 self.track_for_cleanup(self.workspacedir)
895 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
896 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
897 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
898 self.assertExists(os.path.join(tempdir, 'Cargo.toml'), 'Extracted source could not be found')
899 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
900 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'zvariant_*.bbappend'))
901 self.assertTrue(matches, 'bbappend not created')
902 # Test devtool status
903 result = runCmd('devtool status')
904 self.assertIn(testrecipe, result.output)
905 self.assertIn(tempdir, result.output)
906 # Check git repo
907 self._check_src_repo(tempdir)
908 # Check that the patch is correctly applied
909 # last commit message in the tree must contain
910 # %% original patch: <patchname>
911 # ..
912 patchname = None
913 for uri in src_uri:
914 if uri.startswith('file://') and '.patch' in uri:
915 patchname = uri.replace("file://", "").partition('.patch')[0] + '.patch'
916 self.assertIsNotNone(patchname)
917 result = runCmd('git -C %s log -1' % tempdir)
918 self.assertIn("%%%% original patch: %s" % patchname, result.output)
919
920 # Configure the recipe to check that the git dependencies are correctly patched in cargo config
921 bitbake('-c configure %s' % testrecipe)
922
923 cargo_config_path = os.path.join(cargo_home, 'config')
924 with open(cargo_config_path, "r") as f:
925 cargo_config_contents = [line.strip('\n') for line in f.readlines()]
926
927 # Get back git dependencies of the recipe (ignoring the main one)
928 # and check that they are all correctly patched to be fetched locally
929 git_deps = [uri for uri in src_uri if uri.startswith("git://")][1:]
930 for git_dep in git_deps:
931 raw_url, _, raw_parms = git_dep.partition(";")
932 parms = {}
933 for parm in raw_parms.split(";"):
934 name_parm, _, value_parm = parm.partition('=')
935 parms[name_parm]=value_parm
936 self.assertIn('protocol', parms, 'git dependencies uri should contain the "protocol" parameter')
937 self.assertIn('name', parms, 'git dependencies uri should contain the "name" parameter')
938 self.assertIn('destsuffix', parms, 'git dependencies uri should contain the "destsuffix" parameter')
939 self.assertIn('type', parms, 'git dependencies uri should contain the "type" parameter')
940 self.assertEqual(parms['type'], 'git-dependency', 'git dependencies uri should have "type=git-dependency"')
941 raw_url = raw_url.replace("git://", '%s://' % parms['protocol'])
942 patch_line = '[patch."%s"]' % raw_url
943 path_patched = os.path.join(workdir, parms['destsuffix'])
944 path_override_line = '%s = { path = "%s" }' % (parms['name'], path_patched)
945 # Would have been better to use tomllib to read this file :/
946 self.assertIn(patch_line, cargo_config_contents)
947 self.assertIn(path_override_line, cargo_config_contents)
948
949 # Try to package the recipe
950 bitbake('-c package_qa %s' % testrecipe)
951
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500952 def test_devtool_modify_localfiles(self):
953 # Check preconditions
954 testrecipe = 'lighttpd'
955 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
956 foundlocal = False
957 for item in src_uri:
958 if item.startswith('file://') and '.patch' not in item:
959 foundlocal = True
960 break
961 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
962 # Clean up anything in the workdir/sysroot/sstate cache
963 bitbake('%s -c cleansstate' % testrecipe)
964 # Try modifying a recipe
965 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
966 self.track_for_cleanup(tempdir)
967 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500968 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400969 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500970 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
971 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
972 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
973 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
974 self.assertTrue(matches, 'bbappend not created')
975 # Test devtool status
976 result = runCmd('devtool status')
977 self.assertIn(testrecipe, result.output)
978 self.assertIn(tempdir, result.output)
979 # Try building
980 bitbake(testrecipe)
981
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500982 def test_devtool_modify_virtual(self):
983 # Try modifying a virtual recipe
984 virtrecipe = 'virtual/make'
985 realrecipe = 'make'
986 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
987 self.track_for_cleanup(tempdir)
988 self.track_for_cleanup(self.workspacedir)
989 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
990 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
991 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
992 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
993 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
994 self.assertTrue(matches, 'bbappend not created %s' % result.output)
995 # Test devtool status
996 result = runCmd('devtool status')
997 self.assertNotIn(virtrecipe, result.output)
998 self.assertIn(realrecipe, result.output)
999 # Check git repo
1000 self._check_src_repo(tempdir)
1001 # This is probably sufficient
1002
Andrew Geisslerf0343792020-11-18 10:42:21 -06001003 def test_devtool_modify_overrides(self):
1004 # Try modifying a recipe with patches in overrides
1005 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1006 self.track_for_cleanup(tempdir)
1007 self.track_for_cleanup(self.workspacedir)
1008 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1009 result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
1010
1011 self._check_src_repo(tempdir)
1012 source = os.path.join(tempdir, "source")
1013 def check(branch, expected):
1014 runCmd('git -C %s checkout %s' % (tempdir, branch))
1015 with open(source, "rt") as f:
1016 content = f.read()
1017 self.assertEquals(content, expected)
1018 check('devtool', 'This is a test for something\n')
1019 check('devtool-no-overrides', 'This is a test for something\n')
1020 check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
1021 check('devtool-override-qemux86', 'This is a test for qemux86\n')
1022
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001023class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001024
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001025 def test_devtool_update_recipe(self):
1026 # Check preconditions
1027 testrecipe = 'minicom'
1028 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1029 recipefile = bb_vars['FILE']
1030 src_uri = bb_vars['SRC_URI']
1031 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1032 self._check_repo_status(os.path.dirname(recipefile), [])
1033 # First, modify a recipe
1034 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1035 self.track_for_cleanup(tempdir)
1036 self.track_for_cleanup(self.workspacedir)
1037 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1038 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1039 # We don't use -x here so that we test the behaviour of devtool modify without it
1040 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
1041 # Check git repo
1042 self._check_src_repo(tempdir)
1043 # Add a couple of commits
1044 # FIXME: this only tests adding, need to also test update and remove
1045 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
1046 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
1047 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1048 result = runCmd('git add devtool-new-file', cwd=tempdir)
1049 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1050 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1051 result = runCmd('devtool update-recipe %s' % testrecipe)
1052 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1053 ('??', '.*/0001-Change-the-README.patch$'),
1054 ('??', '.*/0002-Add-a-new-file.patch$')]
1055 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1056
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001057 def test_devtool_update_recipe_git(self):
1058 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001059 testrecipe = 'mtd-utils-selftest'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001060 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1061 recipefile = bb_vars['FILE']
1062 src_uri = bb_vars['SRC_URI']
1063 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1064 patches = []
1065 for entry in src_uri.split():
1066 if entry.startswith('file://') and entry.endswith('.patch'):
1067 patches.append(entry[7:].split(';')[0])
1068 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
1069 self._check_repo_status(os.path.dirname(recipefile), [])
1070 # First, modify a recipe
1071 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1072 self.track_for_cleanup(tempdir)
1073 self.track_for_cleanup(self.workspacedir)
1074 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1075 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1076 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1077 # Check git repo
1078 self._check_src_repo(tempdir)
1079 # Add a couple of commits
1080 # FIXME: this only tests adding, need to also test update and remove
1081 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
1082 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
1083 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1084 result = runCmd('git add devtool-new-file', cwd=tempdir)
1085 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1086 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1087 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
1088 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
1089 [(' D', '.*/%s$' % patch) for patch in patches]
1090 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1091
1092 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +00001093 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001094 srcurilines = src_uri.split()
1095 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
1096 srcurilines.append('"')
1097 removelines = ['SRCREV = ".*"'] + srcurilines
Andrew Geissler615f2f12022-07-15 14:00:58 -05001098 self._check_diff(result.output, addlines, removelines)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001099 # Now try with auto mode
1100 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
1101 result = runCmd('devtool update-recipe %s' % testrecipe)
1102 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
1103 topleveldir = result.output.strip()
1104 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
1105 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
1106 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
1107 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
1108 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1109
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001110 def test_devtool_update_recipe_append(self):
1111 # Check preconditions
1112 testrecipe = 'mdadm'
1113 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1114 recipefile = bb_vars['FILE']
1115 src_uri = bb_vars['SRC_URI']
1116 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1117 self._check_repo_status(os.path.dirname(recipefile), [])
1118 # First, modify a recipe
1119 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1120 tempsrcdir = os.path.join(tempdir, 'source')
1121 templayerdir = os.path.join(tempdir, 'layer')
1122 self.track_for_cleanup(tempdir)
1123 self.track_for_cleanup(self.workspacedir)
1124 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1125 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1126 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1127 # Check git repo
1128 self._check_src_repo(tempsrcdir)
1129 # Add a commit
1130 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
1131 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1132 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1133 # Create a temporary layer and add it to bblayers.conf
1134 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
1135 # Create the bbappend
1136 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1137 self.assertNotIn('WARNING:', result.output)
1138 # Check recipe is still clean
1139 self._check_repo_status(os.path.dirname(recipefile), [])
1140 # Check bbappend was created
1141 splitpath = os.path.dirname(recipefile).split(os.sep)
1142 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1143 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1144 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
1145 self.assertExists(patchfile, 'Patch file not created')
1146
1147 # Check bbappend contents
Patrick Williams213cb262021-08-07 19:21:33 -05001148 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001149 '\n',
1150 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
1151 '\n']
1152 with open(bbappendfile, 'r') as f:
1153 self.assertEqual(expectedlines, f.readlines())
1154
1155 # Check we can run it again and bbappend isn't modified
1156 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1157 with open(bbappendfile, 'r') as f:
1158 self.assertEqual(expectedlines, f.readlines())
1159 # Drop new commit and check patch gets deleted
1160 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1161 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1162 self.assertNotExists(patchfile, 'Patch file not deleted')
Patrick Williams213cb262021-08-07 19:21:33 -05001163 expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001164 '\n']
1165 with open(bbappendfile, 'r') as f:
1166 self.assertEqual(expectedlines2, f.readlines())
1167 # Put commit back and check we can run it if layer isn't in bblayers.conf
1168 os.remove(bbappendfile)
1169 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1170 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1171 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1172 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1173 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
1174 with open(bbappendfile, 'r') as f:
1175 self.assertEqual(expectedlines, f.readlines())
1176 # Deleting isn't expected to work under these circumstances
1177
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001178 def test_devtool_update_recipe_append_git(self):
1179 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001180 testrecipe = 'mtd-utils-selftest'
Andrew Geissler517393d2023-01-13 08:55:19 -06001181 bb_vars = get_bb_vars(['FILE', 'SRC_URI', 'LAYERSERIES_CORENAMES'], testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001182 recipefile = bb_vars['FILE']
1183 src_uri = bb_vars['SRC_URI']
Andrew Geissler517393d2023-01-13 08:55:19 -06001184 corenames = bb_vars['LAYERSERIES_CORENAMES']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001185 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1186 for entry in src_uri.split():
1187 if entry.startswith('git://'):
1188 git_uri = entry
1189 break
1190 self._check_repo_status(os.path.dirname(recipefile), [])
1191 # First, modify a recipe
1192 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1193 tempsrcdir = os.path.join(tempdir, 'source')
1194 templayerdir = os.path.join(tempdir, 'layer')
1195 self.track_for_cleanup(tempdir)
1196 self.track_for_cleanup(self.workspacedir)
1197 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1198 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1199 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1200 # Check git repo
1201 self._check_src_repo(tempsrcdir)
1202 # Add a commit
1203 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
1204 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1205 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1206 # Create a temporary layer
1207 os.makedirs(os.path.join(templayerdir, 'conf'))
1208 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
1209 f.write('BBPATH .= ":${LAYERDIR}"\n')
1210 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
1211 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
1212 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
1213 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
1214 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Andrew Geissler517393d2023-01-13 08:55:19 -06001215 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "%s"\n' % corenames)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001216 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
1217 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
1218 # Create the bbappend
1219 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1220 self.assertNotIn('WARNING:', result.output)
1221 # Check recipe is still clean
1222 self._check_repo_status(os.path.dirname(recipefile), [])
1223 # Check bbappend was created
1224 splitpath = os.path.dirname(recipefile).split(os.sep)
1225 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1226 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1227 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1228
1229 # Check bbappend contents
1230 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1231 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1232 '\n',
1233 'SRC_URI = "%s"\n' % git_uri,
1234 '\n'])
1235 with open(bbappendfile, 'r') as f:
1236 self.assertEqual(expectedlines, set(f.readlines()))
1237
1238 # Check we can run it again and bbappend isn't modified
1239 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1240 with open(bbappendfile, 'r') as f:
1241 self.assertEqual(expectedlines, set(f.readlines()))
1242 # Drop new commit and check SRCREV changes
1243 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1244 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1245 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1246 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1247 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1248 '\n',
1249 'SRC_URI = "%s"\n' % git_uri,
1250 '\n'])
1251 with open(bbappendfile, 'r') as f:
1252 self.assertEqual(expectedlines, set(f.readlines()))
1253 # Put commit back and check we can run it if layer isn't in bblayers.conf
1254 os.remove(bbappendfile)
1255 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1256 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1257 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1258 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1259 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1260 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1261 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1262 '\n',
1263 'SRC_URI = "%s"\n' % git_uri,
1264 '\n'])
1265 with open(bbappendfile, 'r') as f:
1266 self.assertEqual(expectedlines, set(f.readlines()))
1267 # Deleting isn't expected to work under these circumstances
1268
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001269 def test_devtool_update_recipe_local_files(self):
1270 """Check that local source files are copied over instead of patched"""
1271 testrecipe = 'makedevs'
1272 recipefile = get_bb_var('FILE', testrecipe)
1273 # Setup srctree for modifying the recipe
1274 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1275 self.track_for_cleanup(tempdir)
1276 self.track_for_cleanup(self.workspacedir)
1277 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1278 # (don't bother with cleaning the recipe on teardown, we won't be
1279 # building it)
1280 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1281 # Check git repo
1282 self._check_src_repo(tempdir)
1283 # Try building just to ensure we haven't broken that
1284 bitbake("%s" % testrecipe)
1285 # Edit / commit local source
1286 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1287 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1288 runCmd('echo "Bar" > new-file', cwd=tempdir)
1289 runCmd('git add new-file', cwd=tempdir)
1290 runCmd('git commit -m "Add new file"', cwd=tempdir)
1291 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1292 os.path.dirname(recipefile))
1293 runCmd('devtool update-recipe %s' % testrecipe)
1294 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1295 (' M', '.*/makedevs/makedevs.c$'),
1296 ('??', '.*/makedevs/new-local$'),
1297 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1298 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1299
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001300 def test_devtool_update_recipe_local_files_2(self):
1301 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001302 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001303 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001304 recipedir = os.path.dirname(recipefile)
1305 result = runCmd('git status --porcelain .', cwd=recipedir)
1306 if result.output.strip():
1307 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001308 # Setup srctree for modifying the recipe
1309 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1310 self.track_for_cleanup(tempdir)
1311 self.track_for_cleanup(self.workspacedir)
1312 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1313 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1314 # Check git repo
1315 self._check_src_repo(tempdir)
1316 # Add oe-local-files to Git
1317 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1318 runCmd('git add oe-local-files', cwd=tempdir)
1319 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1320 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001321 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001322 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001323 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001324 runCmd('git commit -m"Remove file"', cwd=tempdir)
1325 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1326 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1327 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1328 runCmd('echo "Gar" > new-file', cwd=tempdir)
1329 runCmd('git add new-file', cwd=tempdir)
1330 runCmd('git commit -m "Add new file"', cwd=tempdir)
1331 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1332 os.path.dirname(recipefile))
1333 # Checkout unmodified file to working copy -> devtool should still pick
1334 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001335 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001336 runCmd('devtool update-recipe %s' % testrecipe)
1337 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001338 (' M', '.*/file1$'),
1339 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001340 ('??', '.*/new-local$'),
1341 ('??', '.*/0001-Add-new-file.patch$')]
1342 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1343
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001344 def test_devtool_update_recipe_with_gitignore(self):
1345 # First, modify the recipe
1346 testrecipe = 'devtool-test-ignored'
1347 bb_vars = get_bb_vars(['FILE'], testrecipe)
1348 recipefile = bb_vars['FILE']
1349 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1350 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
1351 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1352 self.track_for_cleanup(tempdir)
1353 self.track_for_cleanup(self.workspacedir)
1354 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1355 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1356 result = runCmd('devtool modify %s' % testrecipe)
1357 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1358 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1359 # Check recipe got changed as expected
1360 with open(newpatchfile, 'r') as f:
1361 desiredlines = f.readlines()
1362 with open(patchfile, 'r') as f:
1363 newlines = f.readlines()
1364 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1365 # which changes the metadata subject which is added into the patch, but keep
1366 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1367 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1368 self.assertEqual(desiredlines[5:], newlines[5:])
1369
1370 def test_devtool_update_recipe_long_filename(self):
1371 # First, modify the recipe
1372 testrecipe = 'devtool-test-long-filename'
1373 bb_vars = get_bb_vars(['FILE'], testrecipe)
1374 recipefile = bb_vars['FILE']
1375 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1376 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1377 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1378 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1379 self.track_for_cleanup(tempdir)
1380 self.track_for_cleanup(self.workspacedir)
1381 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1382 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1383 result = runCmd('devtool modify %s' % testrecipe)
1384 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1385 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1386 # Check recipe got changed as expected
1387 with open(newpatchfile, 'r') as f:
1388 desiredlines = f.readlines()
1389 with open(patchfile, 'r') as f:
1390 newlines = f.readlines()
1391 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1392 # which changes the metadata subject which is added into the patch, but keep
1393 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1394 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1395 self.assertEqual(desiredlines[5:], newlines[5:])
1396
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001397 def test_devtool_update_recipe_local_files_3(self):
1398 # First, modify the recipe
1399 testrecipe = 'devtool-test-localonly'
1400 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1401 recipefile = bb_vars['FILE']
1402 src_uri = bb_vars['SRC_URI']
1403 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1404 self.track_for_cleanup(tempdir)
1405 self.track_for_cleanup(self.workspacedir)
1406 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1407 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1408 result = runCmd('devtool modify %s' % testrecipe)
1409 # Modify one file
1410 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1411 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1412 result = runCmd('devtool update-recipe %s' % testrecipe)
1413 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1414 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1415
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001416 def test_devtool_update_recipe_local_patch_gz(self):
1417 # First, modify the recipe
1418 testrecipe = 'devtool-test-patch-gz'
1419 if get_bb_var('DISTRO') == 'poky-tiny':
1420 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1421 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1422 recipefile = bb_vars['FILE']
1423 src_uri = bb_vars['SRC_URI']
1424 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1425 self.track_for_cleanup(tempdir)
1426 self.track_for_cleanup(self.workspacedir)
1427 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1428 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1429 result = runCmd('devtool modify %s' % testrecipe)
1430 # Modify one file
1431 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1432 runCmd('echo "Another line" >> README', cwd=srctree)
1433 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1434 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1435 result = runCmd('devtool update-recipe %s' % testrecipe)
1436 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1437 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1438 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1439 result = runCmd('file %s' % patch_gz)
1440 if 'gzip compressed data' not in result.output:
1441 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1442
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001443 def test_devtool_update_recipe_local_files_subdir(self):
1444 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1445 # SRC_URI such that it overwrites a file that was in an archive that
1446 # was also in SRC_URI
1447 # First, modify the recipe
1448 testrecipe = 'devtool-test-subdir'
1449 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1450 recipefile = bb_vars['FILE']
1451 src_uri = bb_vars['SRC_URI']
1452 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1453 self.track_for_cleanup(tempdir)
1454 self.track_for_cleanup(self.workspacedir)
1455 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1456 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1457 result = runCmd('devtool modify %s' % testrecipe)
1458 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1459 self.assertExists(testfile, 'Extracted source could not be found')
1460 with open(testfile, 'r') as f:
1461 contents = f.read().rstrip()
1462 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1463 # Test devtool update-recipe without modifying any files
1464 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1465 result = runCmd('devtool update-recipe %s' % testrecipe)
1466 expected_status = []
1467 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1468
Andrew Geissler615f2f12022-07-15 14:00:58 -05001469 def test_devtool_finish_modify_git_subdir(self):
1470 # Check preconditions
1471 testrecipe = 'dos2unix'
1472 bb_vars = get_bb_vars(['SRC_URI', 'S', 'WORKDIR', 'FILE'], testrecipe)
1473 self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe)
1474 workdir_git = '%s/git/' % bb_vars['WORKDIR']
1475 if not bb_vars['S'].startswith(workdir_git):
1476 self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe)
1477 subdir = bb_vars['S'].split(workdir_git, 1)[1]
1478 # Clean up anything in the workdir/sysroot/sstate cache
1479 bitbake('%s -c cleansstate' % testrecipe)
1480 # Try modifying a recipe
1481 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1482 self.track_for_cleanup(tempdir)
1483 self.track_for_cleanup(self.workspacedir)
1484 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1485 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1486 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1487 testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c')
1488 self.assertExists(testsrcfile, 'Extracted source could not be found')
1489 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
1490 self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo')
1491 # Check git repo
1492 self._check_src_repo(tempdir)
1493 # Modify file
1494 runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile)
1495 result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir)
1496 # Now try updating original recipe
1497 recipefile = bb_vars['FILE']
1498 recipedir = os.path.dirname(recipefile)
1499 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1500 result = runCmd('devtool update-recipe %s' % testrecipe)
1501 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1502 ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))]
1503 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1504 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
1505 removelines = ['SRC_URI = "git://.*"']
1506 addlines = [
1507 'SRC_URI = "git://.* \\\\',
1508 'file://0001-Add-a-comment.patch;patchdir=.. \\\\',
1509 '"'
1510 ]
1511 self._check_diff(result.output, addlines, removelines)
1512 # Put things back so we can run devtool finish on a different layer
1513 runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1514 # Run devtool finish
1515 res = re.search('recipes-.*', recipedir)
1516 self.assertTrue(res, 'Unable to find recipe subdirectory')
1517 recipesubdir = res[0]
1518 self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir))
1519 result = runCmd('devtool finish %s meta-selftest' % testrecipe)
1520 # Check bbappend file contents
1521 appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe)
1522 with open(appendfn, 'r') as f:
1523 appendlines = f.readlines()
1524 expected_appendlines = [
1525 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
1526 '\n',
1527 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n',
1528 '\n'
1529 ]
1530 self.assertEqual(appendlines, expected_appendlines)
1531 self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch'))
1532 # Try building
1533 bitbake('%s -c patch' % testrecipe)
1534
1535
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001536class DevtoolExtractTests(DevtoolBase):
1537
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001538 def test_devtool_extract(self):
1539 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1540 # Try devtool extract
1541 self.track_for_cleanup(tempdir)
1542 self.track_for_cleanup(self.workspacedir)
1543 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1544 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1545 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1546 self._check_src_repo(tempdir)
1547
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001548 def test_devtool_extract_virtual(self):
1549 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1550 # Try devtool extract
1551 self.track_for_cleanup(tempdir)
1552 self.track_for_cleanup(self.workspacedir)
1553 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1554 result = runCmd('devtool extract virtual/make %s' % tempdir)
1555 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1556 self._check_src_repo(tempdir)
1557
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001558 def test_devtool_reset_all(self):
1559 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1560 self.track_for_cleanup(tempdir)
1561 self.track_for_cleanup(self.workspacedir)
1562 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1563 testrecipe1 = 'mdadm'
1564 testrecipe2 = 'cronie'
1565 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1566 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1567 result = runCmd('devtool build %s' % testrecipe1)
1568 result = runCmd('devtool build %s' % testrecipe2)
1569 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1570 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1571 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1572 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1573 result = runCmd('devtool reset -a')
1574 self.assertIn(testrecipe1, result.output)
1575 self.assertIn(testrecipe2, result.output)
1576 result = runCmd('devtool status')
1577 self.assertNotIn(testrecipe1, result.output)
1578 self.assertNotIn(testrecipe2, result.output)
1579 matches1 = glob.glob(stampprefix1 + '*')
1580 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1581 matches2 = glob.glob(stampprefix2 + '*')
1582 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1583
Patrick Williams45852732022-04-02 08:58:32 -05001584 @OETestTag("runqemu")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001585 def test_devtool_deploy_target(self):
1586 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1587 # unfortunately the runtime tests run under bitbake and you can't run
1588 # devtool within bitbake (since devtool needs to run bitbake itself).
1589 # Additionally we are testing build-time functionality as well, so
1590 # really this has to be done as an oe-selftest test.
1591 #
1592 # Check preconditions
1593 machine = get_bb_var('MACHINE')
1594 if not machine.startswith('qemu'):
1595 self.skipTest('This test only works with qemu machines')
1596 if not os.path.exists('/etc/runqemu-nosudo'):
1597 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1598 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1599 if result.status != 0:
1600 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1601 if result.status != 0:
1602 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1603 for line in result.output.splitlines():
1604 if line.startswith('tap'):
1605 break
1606 else:
1607 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1608 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1609 # Definitions
1610 testrecipe = 'mdadm'
1611 testfile = '/sbin/mdadm'
1612 testimage = 'oe-selftest-image'
1613 testcommand = '/sbin/mdadm --help'
1614 # Build an image to run
1615 bitbake("%s qemu-native qemu-helper-native" % testimage)
1616 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1617 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1618 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1619 # Clean recipe so the first deploy will fail
1620 bitbake("%s -c clean" % testrecipe)
1621 # Try devtool modify
1622 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1623 self.track_for_cleanup(tempdir)
1624 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001625 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001626 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001627 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1628 # Test that deploy-target at this point fails (properly)
1629 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1630 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1631 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1632 result = runCmd('devtool build %s' % testrecipe)
1633 # First try a dry-run of deploy-target
1634 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1635 self.assertIn(' %s' % testfile, result.output)
1636 # Boot the image
1637 with runqemu(testimage) as qemu:
1638 # Now really test deploy-target
1639 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1640 # Run a test command to see if it was installed properly
1641 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1642 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1643 # Check if it deployed all of the files with the right ownership/perms
1644 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1645 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1646 installdir = bb_vars['D']
1647 fakerootenv = bb_vars['FAKEROOTENV']
1648 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001649 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001650 filelist1 = self._process_ls_output(result.output)
1651
1652 # Now look on the target
1653 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1654 self.track_for_cleanup(tempdir2)
1655 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1656 with open(tmpfilelist, 'w') as f:
1657 for line in filelist1:
1658 splitline = line.split()
1659 f.write(splitline[-1] + '\n')
1660 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1661 filelist2 = self._process_ls_output(result.output)
1662 filelist1.sort(key=lambda item: item.split()[-1])
1663 filelist2.sort(key=lambda item: item.split()[-1])
1664 self.assertEqual(filelist1, filelist2)
1665 # Test undeploy-target
1666 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1667 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1668 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1669
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001670 def test_devtool_build_image(self):
1671 """Test devtool build-image plugin"""
1672 # Check preconditions
1673 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1674 image = 'core-image-minimal'
1675 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001676 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001677 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001678 bitbake('%s -c clean' % image)
1679 # Add target and native recipes to workspace
1680 recipes = ['mdadm', 'parted-native']
1681 for recipe in recipes:
1682 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1683 self.track_for_cleanup(tempdir)
1684 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1685 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1686 # Try to build image
1687 result = runCmd('devtool build-image %s' % image)
1688 self.assertNotEqual(result, 0, 'devtool build-image failed')
1689 # Check if image contains expected packages
1690 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1691 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1692 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1693 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1694 for line in f:
1695 splitval = line.split()
1696 if splitval:
1697 pkg = splitval[0]
1698 if pkg in reqpkgs:
1699 reqpkgs.remove(pkg)
1700 if reqpkgs:
1701 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1702
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001703class DevtoolUpgradeTests(DevtoolBase):
1704
Patrick Williams45852732022-04-02 08:58:32 -05001705 def setUp(self):
1706 super().setUp()
1707 try:
1708 runCmd("git config --global user.name")
1709 runCmd("git config --global user.email")
1710 except:
1711 self.skip("Git user.name and user.email must be set")
1712
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001713 def test_devtool_upgrade(self):
1714 # Check preconditions
1715 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1716 self.track_for_cleanup(self.workspacedir)
1717 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1718 # Check parameters
1719 result = runCmd('devtool upgrade -h')
1720 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1721 self.assertIn(param, result.output)
1722 # For the moment, we are using a real recipe.
1723 recipe = 'devtool-upgrade-test1'
1724 version = '1.6.0'
1725 oldrecipefile = get_bb_var('FILE', recipe)
1726 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1727 self.track_for_cleanup(tempdir)
1728 # Check that recipe is not already under devtool control
1729 result = runCmd('devtool status')
1730 self.assertNotIn(recipe, result.output)
1731 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1732 # we are downgrading instead of upgrading.
1733 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1734 # Check if srctree at least is populated
1735 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1736 # Check new recipe subdirectory is present
1737 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1738 # Check new recipe file is present
1739 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1740 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1741 # Check devtool status and make sure recipe is present
1742 result = runCmd('devtool status')
1743 self.assertIn(recipe, result.output)
1744 self.assertIn(tempdir, result.output)
1745 # Check recipe got changed as expected
1746 with open(oldrecipefile + '.upgraded', 'r') as f:
1747 desiredlines = f.readlines()
1748 with open(newrecipefile, 'r') as f:
1749 newlines = f.readlines()
1750 self.assertEqual(desiredlines, newlines)
1751 # Check devtool reset recipe
1752 result = runCmd('devtool reset %s -n' % recipe)
1753 result = runCmd('devtool status')
1754 self.assertNotIn(recipe, result.output)
1755 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1756
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001757 def test_devtool_upgrade_git(self):
1758 # Check preconditions
1759 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1760 self.track_for_cleanup(self.workspacedir)
1761 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1762 recipe = 'devtool-upgrade-test2'
1763 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1764 oldrecipefile = get_bb_var('FILE', recipe)
1765 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1766 self.track_for_cleanup(tempdir)
1767 # Check that recipe is not already under devtool control
1768 result = runCmd('devtool status')
1769 self.assertNotIn(recipe, result.output)
1770 # Check upgrade
1771 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1772 # Check if srctree at least is populated
1773 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1774 # Check new recipe file is present
1775 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1776 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1777 # Check devtool status and make sure recipe is present
1778 result = runCmd('devtool status')
1779 self.assertIn(recipe, result.output)
1780 self.assertIn(tempdir, result.output)
1781 # Check recipe got changed as expected
1782 with open(oldrecipefile + '.upgraded', 'r') as f:
1783 desiredlines = f.readlines()
1784 with open(newrecipefile, 'r') as f:
1785 newlines = f.readlines()
1786 self.assertEqual(desiredlines, newlines)
1787 # Check devtool reset recipe
1788 result = runCmd('devtool reset %s -n' % recipe)
1789 result = runCmd('devtool status')
1790 self.assertNotIn(recipe, result.output)
1791 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1792
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001793 def test_devtool_layer_plugins(self):
1794 """Test that devtool can use plugins from other layers.
1795
1796 This test executes the selftest-reverse command from meta-selftest."""
1797
1798 self.track_for_cleanup(self.workspacedir)
1799 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1800
1801 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1802 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1803 self.assertEqual(result.output, s[::-1])
1804
1805 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1806 dstdir = basedstdir
1807 self.assertExists(dstdir)
1808 for p in paths:
1809 dstdir = os.path.join(dstdir, p)
1810 if not os.path.exists(dstdir):
1811 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001812 if p == "lib":
1813 # Can race with other tests
1814 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1815 else:
1816 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001817 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1818 if srcfile != dstfile:
1819 shutil.copy(srcfile, dstfile)
1820 self.track_for_cleanup(dstfile)
1821
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001822 def test_devtool_load_plugin(self):
1823 """Test that devtool loads only the first found plugin in BBPATH."""
1824
1825 self.track_for_cleanup(self.workspacedir)
1826 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1827
1828 devtool = runCmd("which devtool")
1829 fromname = runCmd("devtool --quiet pluginfile")
1830 srcfile = fromname.output
1831 bbpath = get_bb_var('BBPATH')
1832 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1833 plugincontent = []
1834 with open(srcfile) as fh:
1835 plugincontent = fh.readlines()
1836 try:
1837 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1838 for path in searchpath:
1839 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1840 result = runCmd("devtool --quiet count")
1841 self.assertEqual(result.output, '1')
1842 result = runCmd("devtool --quiet multiloaded")
1843 self.assertEqual(result.output, "no")
1844 for path in searchpath:
1845 result = runCmd("devtool --quiet bbdir")
1846 self.assertEqual(result.output, path)
1847 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1848 finally:
1849 with open(srcfile, 'w') as fh:
1850 fh.writelines(plugincontent)
1851
1852 def _setup_test_devtool_finish_upgrade(self):
1853 # Check preconditions
1854 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1855 self.track_for_cleanup(self.workspacedir)
1856 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1857 # Use a "real" recipe from meta-selftest
1858 recipe = 'devtool-upgrade-test1'
1859 oldversion = '1.5.3'
1860 newversion = '1.6.0'
1861 oldrecipefile = get_bb_var('FILE', recipe)
1862 recipedir = os.path.dirname(oldrecipefile)
1863 result = runCmd('git status --porcelain .', cwd=recipedir)
1864 if result.output.strip():
1865 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1866 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1867 self.track_for_cleanup(tempdir)
1868 # Check that recipe is not already under devtool control
1869 result = runCmd('devtool status')
1870 self.assertNotIn(recipe, result.output)
1871 # Do the upgrade
1872 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1873 # Check devtool status and make sure recipe is present
1874 result = runCmd('devtool status')
1875 self.assertIn(recipe, result.output)
1876 self.assertIn(tempdir, result.output)
1877 # Make a change to the source
1878 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1879 result = runCmd('git status --porcelain', cwd=tempdir)
1880 self.assertIn('M src/pv/number.c', result.output)
1881 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1882 # Check if patch is there
1883 recipedir = os.path.dirname(oldrecipefile)
1884 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1885 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001886 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001887 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001888 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1889 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001890
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001891 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001892 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001893 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1894 self.assertIn('/meta-selftest/', recipedir)
1895 # Try finish to the original layer
1896 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1897 result = runCmd('devtool finish %s meta-selftest' % recipe)
1898 result = runCmd('devtool status')
1899 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1900 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1901 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1902 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001903 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 -05001904 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1905 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1906 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1907 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 -05001908 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 -05001909 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 -05001910 with open(newrecipefile, 'r') as f:
1911 newcontent = f.read()
1912 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1913 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1914 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1915 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1916
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001917
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001918 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001919 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001920 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1921 self.assertIn('/meta-selftest/', recipedir)
1922 # Try finish to a different layer - should create a bbappend
1923 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1924 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1925 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1926 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1927 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1928 self.track_for_cleanup(newrecipedir)
1929 result = runCmd('devtool finish %s oe-core' % recipe)
1930 result = runCmd('devtool status')
1931 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1932 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1933 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1934 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001935 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001936 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1937 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1938 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 -05001939 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 -05001940 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 -05001941 with open(newrecipefile, 'r') as f:
1942 newcontent = f.read()
1943 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1944 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1945 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1946 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 -05001947
1948 def _setup_test_devtool_finish_modify(self):
1949 # Check preconditions
1950 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1951 # Try modifying a recipe
1952 self.track_for_cleanup(self.workspacedir)
1953 recipe = 'mdadm'
1954 oldrecipefile = get_bb_var('FILE', recipe)
1955 recipedir = os.path.dirname(oldrecipefile)
1956 result = runCmd('git status --porcelain .', cwd=recipedir)
1957 if result.output.strip():
1958 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1959 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1960 self.track_for_cleanup(tempdir)
1961 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1962 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1963 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1964 # Test devtool status
1965 result = runCmd('devtool status')
1966 self.assertIn(recipe, result.output)
1967 self.assertIn(tempdir, result.output)
1968 # Make a change to the source
1969 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1970 result = runCmd('git status --porcelain', cwd=tempdir)
1971 self.assertIn('M maps.c', result.output)
1972 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1973 for entry in os.listdir(recipedir):
1974 filesdir = os.path.join(recipedir, entry)
1975 if os.path.isdir(filesdir):
1976 break
1977 else:
1978 self.fail('Unable to find recipe files directory for %s' % recipe)
1979 return recipe, oldrecipefile, recipedir, filesdir
1980
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001981 def test_devtool_finish_modify_origlayer(self):
1982 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1983 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1984 self.assertIn('/meta/', recipedir)
1985 # Try finish to the original layer
1986 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1987 result = runCmd('devtool finish %s meta' % recipe)
1988 result = runCmd('devtool status')
1989 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1990 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1991 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1992 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1993 self._check_repo_status(recipedir, expected_status)
1994
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001995 def test_devtool_finish_modify_otherlayer(self):
1996 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1997 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1998 self.assertIn('/meta/', recipedir)
1999 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
2000 appenddir = os.path.join(get_test_layer(), relpth)
2001 self.track_for_cleanup(appenddir)
2002 # Try finish to the original layer
2003 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2004 result = runCmd('devtool finish %s meta-selftest' % recipe)
2005 result = runCmd('devtool status')
2006 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2007 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2008 result = runCmd('git status --porcelain .', cwd=recipedir)
2009 if result.output.strip():
2010 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
2011 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
2012 recipefn = recipefn.split('_')[0] + '_%'
2013 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
2014 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
2015 newdir = os.path.join(appenddir, recipe)
2016 files = os.listdir(newdir)
2017 foundpatch = None
2018 for fn in files:
2019 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
2020 foundpatch = fn
2021 if not foundpatch:
2022 self.fail('No patch file created next to bbappend')
2023 files.remove(foundpatch)
2024 if files:
2025 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
2026
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002027 def test_devtool_rename(self):
2028 # Check preconditions
2029 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
2030 self.track_for_cleanup(self.workspacedir)
2031 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
2032
2033 # First run devtool add
2034 # We already have this recipe in OE-Core, but that doesn't matter
2035 recipename = 'i2c-tools'
2036 recipever = '3.1.2'
2037 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
2038 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
2039 def add_recipe():
2040 result = runCmd('devtool add %s' % url)
2041 self.assertExists(recipefile, 'Expected recipe file not created')
2042 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
2043 checkvars = {}
2044 checkvars['S'] = None
2045 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2046 self._test_recipe_contents(recipefile, checkvars, [])
2047 add_recipe()
2048 # Now rename it - change both name and version
2049 newrecipename = 'mynewrecipe'
2050 newrecipever = '456'
2051 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
2052 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
2053 self.assertExists(newrecipefile, 'Recipe file not renamed')
2054 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2055 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
2056 self.assertExists(newsrctree, 'Source directory not renamed')
2057 checkvars = {}
2058 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
2059 checkvars['SRC_URI'] = url
2060 self._test_recipe_contents(newrecipefile, checkvars, [])
2061 # Try again - change just name this time
2062 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002063 add_recipe()
2064 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
2065 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
2066 self.assertExists(newrecipefile, 'Recipe file not renamed')
2067 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2068 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
2069 checkvars = {}
2070 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
2071 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2072 self._test_recipe_contents(newrecipefile, checkvars, [])
2073 # Try again - change just version this time
2074 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002075 add_recipe()
2076 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
2077 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
2078 self.assertExists(newrecipefile, 'Recipe file not renamed')
2079 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
2080 checkvars = {}
2081 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
2082 checkvars['SRC_URI'] = url
2083 self._test_recipe_contents(newrecipefile, checkvars, [])
2084
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002085 def test_devtool_virtual_kernel_modify(self):
2086 """
2087 Summary: The purpose of this test case is to verify that
2088 devtool modify works correctly when building
2089 the kernel.
2090 Dependencies: NA
2091 Steps: 1. Build kernel with bitbake.
2092 2. Save the config file generated.
2093 3. Clean the environment.
2094 4. Use `devtool modify virtual/kernel` to validate following:
2095 4.1 The source is checked out correctly.
2096 4.2 The resulting configuration is the same as
2097 what was get on step 2.
2098 4.3 The Kernel can be build correctly.
2099 4.4 Changes made on the source are reflected on the
2100 subsequent builds.
2101 4.5 Changes on the configuration are reflected on the
2102 subsequent builds
2103 Expected: devtool modify is able to checkout the source of the kernel
2104 and modification to the source and configurations are reflected
2105 when building the kernel.
Patrick Williams45852732022-04-02 08:58:32 -05002106 """
2107 kernel_provider = self.td['PREFERRED_PROVIDER_virtual/kernel']
2108
Andrew Geissler82c905d2020-04-13 13:39:40 -05002109 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002110 bitbake('%s -c clean' % kernel_provider)
2111 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2112 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
2113 self.track_for_cleanup(tempdir)
2114 self.track_for_cleanup(tempdir_cfg)
2115 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002116 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04002117 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002118 #Step 1
2119 #Here is just generated the config file instead of all the kernel to optimize the
2120 #time of executing this test case.
2121 bitbake('%s -c configure' % kernel_provider)
2122 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
2123 #Step 2
2124 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
2125 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
2126
2127 tmpconfig = os.path.join(tempdir_cfg, '.config')
2128 #Step 3
2129 bitbake('%s -c clean' % kernel_provider)
2130 #Step 4.1
2131 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
2132 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2133 #Step 4.2
2134 configfile = os.path.join(tempdir,'.config')
Patrick Williams45852732022-04-02 08:58:32 -05002135 runCmd('diff %s %s' % (tmpconfig, configfile))
2136
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002137 #Step 4.3
2138 #NOTE: virtual/kernel is mapped to kernel_provider
Patrick Williams45852732022-04-02 08:58:32 -05002139 runCmd('devtool build %s' % kernel_provider)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002140 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
2141 self.assertExists(kernelfile, 'Kernel was not build correctly')
2142
2143 #Modify the kernel source
Patrick Williams45852732022-04-02 08:58:32 -05002144 modfile = os.path.join(tempdir, 'init/version.c')
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002145 # Moved to uts.h in 6.1 onwards
2146 modfile2 = os.path.join(tempdir, 'include/linux/uts.h')
2147 runCmd("sed -i 's/Linux/LiNuX/g' %s %s" % (modfile, modfile2))
Patrick Williams45852732022-04-02 08:58:32 -05002148
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002149 #Modify the configuration
Patrick Williams45852732022-04-02 08:58:32 -05002150 codeconfigfile = os.path.join(tempdir, '.config.new')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002151 modconfopt = "CONFIG_SG_POOL=n"
Patrick Williams45852732022-04-02 08:58:32 -05002152 runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
2153
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002154 #Build again kernel with devtool
Patrick Williams45852732022-04-02 08:58:32 -05002155 runCmd('devtool build %s' % kernel_provider)
2156
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002157 #Step 4.4
Patrick Williams45852732022-04-02 08:58:32 -05002158 runCmd("grep '%s' %s" % ('LiNuX', kernelfile))
2159
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002160 #Step 4.5
Patrick Williams45852732022-04-02 08:58:32 -05002161 runCmd("grep %s %s" % (modconfopt, codeconfigfile))