blob: 4c8e375d007756db513cb1b914abd04c29f567bd [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'
Patrick Williams520786c2023-06-25 16:20:36 -05001472 self.append_config('ERROR_QA:remove:pn-dos2unix = "patch-status"\n')
Andrew Geissler615f2f12022-07-15 14:00:58 -05001473 bb_vars = get_bb_vars(['SRC_URI', 'S', 'WORKDIR', 'FILE'], testrecipe)
1474 self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe)
1475 workdir_git = '%s/git/' % bb_vars['WORKDIR']
1476 if not bb_vars['S'].startswith(workdir_git):
1477 self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe)
1478 subdir = bb_vars['S'].split(workdir_git, 1)[1]
1479 # Clean up anything in the workdir/sysroot/sstate cache
1480 bitbake('%s -c cleansstate' % testrecipe)
1481 # Try modifying a recipe
1482 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1483 self.track_for_cleanup(tempdir)
1484 self.track_for_cleanup(self.workspacedir)
1485 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1486 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1487 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1488 testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c')
1489 self.assertExists(testsrcfile, 'Extracted source could not be found')
1490 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
1491 self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo')
1492 # Check git repo
1493 self._check_src_repo(tempdir)
1494 # Modify file
1495 runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile)
1496 result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir)
1497 # Now try updating original recipe
1498 recipefile = bb_vars['FILE']
1499 recipedir = os.path.dirname(recipefile)
1500 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1501 result = runCmd('devtool update-recipe %s' % testrecipe)
1502 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1503 ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))]
1504 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1505 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
1506 removelines = ['SRC_URI = "git://.*"']
1507 addlines = [
1508 'SRC_URI = "git://.* \\\\',
1509 'file://0001-Add-a-comment.patch;patchdir=.. \\\\',
1510 '"'
1511 ]
1512 self._check_diff(result.output, addlines, removelines)
1513 # Put things back so we can run devtool finish on a different layer
1514 runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1515 # Run devtool finish
1516 res = re.search('recipes-.*', recipedir)
1517 self.assertTrue(res, 'Unable to find recipe subdirectory')
1518 recipesubdir = res[0]
1519 self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir))
1520 result = runCmd('devtool finish %s meta-selftest' % testrecipe)
1521 # Check bbappend file contents
1522 appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe)
1523 with open(appendfn, 'r') as f:
1524 appendlines = f.readlines()
1525 expected_appendlines = [
1526 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
1527 '\n',
1528 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n',
1529 '\n'
1530 ]
1531 self.assertEqual(appendlines, expected_appendlines)
1532 self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch'))
1533 # Try building
1534 bitbake('%s -c patch' % testrecipe)
1535
1536
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001537class DevtoolExtractTests(DevtoolBase):
1538
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001539 def test_devtool_extract(self):
1540 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1541 # Try devtool extract
1542 self.track_for_cleanup(tempdir)
1543 self.track_for_cleanup(self.workspacedir)
1544 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1545 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1546 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1547 self._check_src_repo(tempdir)
1548
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001549 def test_devtool_extract_virtual(self):
1550 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1551 # Try devtool extract
1552 self.track_for_cleanup(tempdir)
1553 self.track_for_cleanup(self.workspacedir)
1554 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1555 result = runCmd('devtool extract virtual/make %s' % tempdir)
1556 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1557 self._check_src_repo(tempdir)
1558
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001559 def test_devtool_reset_all(self):
1560 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1561 self.track_for_cleanup(tempdir)
1562 self.track_for_cleanup(self.workspacedir)
1563 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1564 testrecipe1 = 'mdadm'
1565 testrecipe2 = 'cronie'
1566 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1567 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1568 result = runCmd('devtool build %s' % testrecipe1)
1569 result = runCmd('devtool build %s' % testrecipe2)
1570 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1571 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1572 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1573 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1574 result = runCmd('devtool reset -a')
1575 self.assertIn(testrecipe1, result.output)
1576 self.assertIn(testrecipe2, result.output)
1577 result = runCmd('devtool status')
1578 self.assertNotIn(testrecipe1, result.output)
1579 self.assertNotIn(testrecipe2, result.output)
1580 matches1 = glob.glob(stampprefix1 + '*')
1581 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1582 matches2 = glob.glob(stampprefix2 + '*')
1583 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1584
Patrick Williams45852732022-04-02 08:58:32 -05001585 @OETestTag("runqemu")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001586 def test_devtool_deploy_target(self):
1587 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1588 # unfortunately the runtime tests run under bitbake and you can't run
1589 # devtool within bitbake (since devtool needs to run bitbake itself).
1590 # Additionally we are testing build-time functionality as well, so
1591 # really this has to be done as an oe-selftest test.
1592 #
1593 # Check preconditions
1594 machine = get_bb_var('MACHINE')
1595 if not machine.startswith('qemu'):
1596 self.skipTest('This test only works with qemu machines')
1597 if not os.path.exists('/etc/runqemu-nosudo'):
1598 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1599 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1600 if result.status != 0:
1601 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1602 if result.status != 0:
1603 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1604 for line in result.output.splitlines():
1605 if line.startswith('tap'):
1606 break
1607 else:
1608 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1609 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1610 # Definitions
1611 testrecipe = 'mdadm'
1612 testfile = '/sbin/mdadm'
1613 testimage = 'oe-selftest-image'
1614 testcommand = '/sbin/mdadm --help'
1615 # Build an image to run
1616 bitbake("%s qemu-native qemu-helper-native" % testimage)
1617 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1618 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1619 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1620 # Clean recipe so the first deploy will fail
1621 bitbake("%s -c clean" % testrecipe)
1622 # Try devtool modify
1623 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1624 self.track_for_cleanup(tempdir)
1625 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001626 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001627 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001628 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1629 # Test that deploy-target at this point fails (properly)
1630 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1631 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1632 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1633 result = runCmd('devtool build %s' % testrecipe)
1634 # First try a dry-run of deploy-target
1635 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1636 self.assertIn(' %s' % testfile, result.output)
1637 # Boot the image
1638 with runqemu(testimage) as qemu:
1639 # Now really test deploy-target
1640 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1641 # Run a test command to see if it was installed properly
1642 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1643 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1644 # Check if it deployed all of the files with the right ownership/perms
1645 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1646 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1647 installdir = bb_vars['D']
1648 fakerootenv = bb_vars['FAKEROOTENV']
1649 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001650 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001651 filelist1 = self._process_ls_output(result.output)
1652
1653 # Now look on the target
1654 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1655 self.track_for_cleanup(tempdir2)
1656 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1657 with open(tmpfilelist, 'w') as f:
1658 for line in filelist1:
1659 splitline = line.split()
1660 f.write(splitline[-1] + '\n')
1661 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1662 filelist2 = self._process_ls_output(result.output)
1663 filelist1.sort(key=lambda item: item.split()[-1])
1664 filelist2.sort(key=lambda item: item.split()[-1])
1665 self.assertEqual(filelist1, filelist2)
1666 # Test undeploy-target
1667 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1668 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1669 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1670
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001671 def test_devtool_build_image(self):
1672 """Test devtool build-image plugin"""
1673 # Check preconditions
1674 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1675 image = 'core-image-minimal'
1676 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001677 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001678 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001679 bitbake('%s -c clean' % image)
1680 # Add target and native recipes to workspace
1681 recipes = ['mdadm', 'parted-native']
1682 for recipe in recipes:
1683 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1684 self.track_for_cleanup(tempdir)
1685 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1686 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1687 # Try to build image
1688 result = runCmd('devtool build-image %s' % image)
1689 self.assertNotEqual(result, 0, 'devtool build-image failed')
1690 # Check if image contains expected packages
1691 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1692 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1693 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1694 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1695 for line in f:
1696 splitval = line.split()
1697 if splitval:
1698 pkg = splitval[0]
1699 if pkg in reqpkgs:
1700 reqpkgs.remove(pkg)
1701 if reqpkgs:
1702 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1703
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001704class DevtoolUpgradeTests(DevtoolBase):
1705
Patrick Williams45852732022-04-02 08:58:32 -05001706 def setUp(self):
1707 super().setUp()
1708 try:
1709 runCmd("git config --global user.name")
1710 runCmd("git config --global user.email")
1711 except:
1712 self.skip("Git user.name and user.email must be set")
1713
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001714 def test_devtool_upgrade(self):
1715 # Check preconditions
1716 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1717 self.track_for_cleanup(self.workspacedir)
1718 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1719 # Check parameters
1720 result = runCmd('devtool upgrade -h')
1721 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1722 self.assertIn(param, result.output)
1723 # For the moment, we are using a real recipe.
1724 recipe = 'devtool-upgrade-test1'
1725 version = '1.6.0'
1726 oldrecipefile = get_bb_var('FILE', recipe)
1727 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1728 self.track_for_cleanup(tempdir)
1729 # Check that recipe is not already under devtool control
1730 result = runCmd('devtool status')
1731 self.assertNotIn(recipe, result.output)
1732 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1733 # we are downgrading instead of upgrading.
1734 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1735 # Check if srctree at least is populated
1736 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1737 # Check new recipe subdirectory is present
1738 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1739 # Check new recipe file is present
1740 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1741 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1742 # Check devtool status and make sure recipe is present
1743 result = runCmd('devtool status')
1744 self.assertIn(recipe, result.output)
1745 self.assertIn(tempdir, result.output)
1746 # Check recipe got changed as expected
1747 with open(oldrecipefile + '.upgraded', 'r') as f:
1748 desiredlines = f.readlines()
1749 with open(newrecipefile, 'r') as f:
1750 newlines = f.readlines()
1751 self.assertEqual(desiredlines, newlines)
1752 # Check devtool reset recipe
1753 result = runCmd('devtool reset %s -n' % recipe)
1754 result = runCmd('devtool status')
1755 self.assertNotIn(recipe, result.output)
1756 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1757
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001758 def test_devtool_upgrade_git(self):
1759 # Check preconditions
1760 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1761 self.track_for_cleanup(self.workspacedir)
1762 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1763 recipe = 'devtool-upgrade-test2'
1764 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1765 oldrecipefile = get_bb_var('FILE', recipe)
1766 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1767 self.track_for_cleanup(tempdir)
1768 # Check that recipe is not already under devtool control
1769 result = runCmd('devtool status')
1770 self.assertNotIn(recipe, result.output)
1771 # Check upgrade
1772 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1773 # Check if srctree at least is populated
1774 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1775 # Check new recipe file is present
1776 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1777 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1778 # Check devtool status and make sure recipe is present
1779 result = runCmd('devtool status')
1780 self.assertIn(recipe, result.output)
1781 self.assertIn(tempdir, result.output)
1782 # Check recipe got changed as expected
1783 with open(oldrecipefile + '.upgraded', 'r') as f:
1784 desiredlines = f.readlines()
1785 with open(newrecipefile, 'r') as f:
1786 newlines = f.readlines()
1787 self.assertEqual(desiredlines, newlines)
1788 # Check devtool reset recipe
1789 result = runCmd('devtool reset %s -n' % recipe)
1790 result = runCmd('devtool status')
1791 self.assertNotIn(recipe, result.output)
1792 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1793
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001794 def test_devtool_layer_plugins(self):
1795 """Test that devtool can use plugins from other layers.
1796
1797 This test executes the selftest-reverse command from meta-selftest."""
1798
1799 self.track_for_cleanup(self.workspacedir)
1800 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1801
1802 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1803 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1804 self.assertEqual(result.output, s[::-1])
1805
1806 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1807 dstdir = basedstdir
1808 self.assertExists(dstdir)
1809 for p in paths:
1810 dstdir = os.path.join(dstdir, p)
1811 if not os.path.exists(dstdir):
1812 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001813 if p == "lib":
1814 # Can race with other tests
1815 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1816 else:
1817 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001818 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1819 if srcfile != dstfile:
1820 shutil.copy(srcfile, dstfile)
1821 self.track_for_cleanup(dstfile)
1822
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001823 def test_devtool_load_plugin(self):
1824 """Test that devtool loads only the first found plugin in BBPATH."""
1825
1826 self.track_for_cleanup(self.workspacedir)
1827 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1828
1829 devtool = runCmd("which devtool")
1830 fromname = runCmd("devtool --quiet pluginfile")
1831 srcfile = fromname.output
1832 bbpath = get_bb_var('BBPATH')
1833 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1834 plugincontent = []
1835 with open(srcfile) as fh:
1836 plugincontent = fh.readlines()
1837 try:
1838 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1839 for path in searchpath:
1840 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1841 result = runCmd("devtool --quiet count")
1842 self.assertEqual(result.output, '1')
1843 result = runCmd("devtool --quiet multiloaded")
1844 self.assertEqual(result.output, "no")
1845 for path in searchpath:
1846 result = runCmd("devtool --quiet bbdir")
1847 self.assertEqual(result.output, path)
1848 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1849 finally:
1850 with open(srcfile, 'w') as fh:
1851 fh.writelines(plugincontent)
1852
1853 def _setup_test_devtool_finish_upgrade(self):
1854 # Check preconditions
1855 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1856 self.track_for_cleanup(self.workspacedir)
1857 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1858 # Use a "real" recipe from meta-selftest
1859 recipe = 'devtool-upgrade-test1'
1860 oldversion = '1.5.3'
1861 newversion = '1.6.0'
1862 oldrecipefile = get_bb_var('FILE', recipe)
1863 recipedir = os.path.dirname(oldrecipefile)
1864 result = runCmd('git status --porcelain .', cwd=recipedir)
1865 if result.output.strip():
1866 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1867 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1868 self.track_for_cleanup(tempdir)
1869 # Check that recipe is not already under devtool control
1870 result = runCmd('devtool status')
1871 self.assertNotIn(recipe, result.output)
1872 # Do the upgrade
1873 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1874 # Check devtool status and make sure recipe is present
1875 result = runCmd('devtool status')
1876 self.assertIn(recipe, result.output)
1877 self.assertIn(tempdir, result.output)
1878 # Make a change to the source
1879 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1880 result = runCmd('git status --porcelain', cwd=tempdir)
1881 self.assertIn('M src/pv/number.c', result.output)
1882 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1883 # Check if patch is there
1884 recipedir = os.path.dirname(oldrecipefile)
1885 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1886 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001887 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001888 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001889 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1890 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001891
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001892 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001893 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001894 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1895 self.assertIn('/meta-selftest/', recipedir)
1896 # Try finish to the original layer
1897 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1898 result = runCmd('devtool finish %s meta-selftest' % recipe)
1899 result = runCmd('devtool status')
1900 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1901 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1902 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1903 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001904 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 -05001905 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1906 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1907 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1908 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 -05001909 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 -05001910 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 -05001911 with open(newrecipefile, 'r') as f:
1912 newcontent = f.read()
1913 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1914 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1915 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1916 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1917
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001918
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001919 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001920 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001921 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1922 self.assertIn('/meta-selftest/', recipedir)
1923 # Try finish to a different layer - should create a bbappend
1924 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1925 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1926 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1927 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1928 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1929 self.track_for_cleanup(newrecipedir)
1930 result = runCmd('devtool finish %s oe-core' % recipe)
1931 result = runCmd('devtool status')
1932 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1933 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1934 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1935 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001936 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001937 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1938 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1939 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 -05001940 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 -05001941 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 -05001942 with open(newrecipefile, 'r') as f:
1943 newcontent = f.read()
1944 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1945 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1946 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1947 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 -05001948
1949 def _setup_test_devtool_finish_modify(self):
1950 # Check preconditions
1951 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1952 # Try modifying a recipe
1953 self.track_for_cleanup(self.workspacedir)
1954 recipe = 'mdadm'
1955 oldrecipefile = get_bb_var('FILE', recipe)
1956 recipedir = os.path.dirname(oldrecipefile)
1957 result = runCmd('git status --porcelain .', cwd=recipedir)
1958 if result.output.strip():
1959 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1960 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1961 self.track_for_cleanup(tempdir)
1962 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1963 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1964 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1965 # Test devtool status
1966 result = runCmd('devtool status')
1967 self.assertIn(recipe, result.output)
1968 self.assertIn(tempdir, result.output)
1969 # Make a change to the source
1970 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1971 result = runCmd('git status --porcelain', cwd=tempdir)
1972 self.assertIn('M maps.c', result.output)
1973 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1974 for entry in os.listdir(recipedir):
1975 filesdir = os.path.join(recipedir, entry)
1976 if os.path.isdir(filesdir):
1977 break
1978 else:
1979 self.fail('Unable to find recipe files directory for %s' % recipe)
1980 return recipe, oldrecipefile, recipedir, filesdir
1981
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001982 def test_devtool_finish_modify_origlayer(self):
1983 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1984 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1985 self.assertIn('/meta/', recipedir)
1986 # Try finish to the original layer
1987 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1988 result = runCmd('devtool finish %s meta' % recipe)
1989 result = runCmd('devtool status')
1990 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1991 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1992 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1993 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1994 self._check_repo_status(recipedir, expected_status)
1995
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001996 def test_devtool_finish_modify_otherlayer(self):
1997 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1998 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1999 self.assertIn('/meta/', recipedir)
2000 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
2001 appenddir = os.path.join(get_test_layer(), relpth)
2002 self.track_for_cleanup(appenddir)
2003 # Try finish to the original layer
2004 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
2005 result = runCmd('devtool finish %s meta-selftest' % recipe)
2006 result = runCmd('devtool status')
2007 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
2008 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2009 result = runCmd('git status --porcelain .', cwd=recipedir)
2010 if result.output.strip():
2011 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
2012 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
2013 recipefn = recipefn.split('_')[0] + '_%'
2014 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
2015 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
2016 newdir = os.path.join(appenddir, recipe)
2017 files = os.listdir(newdir)
2018 foundpatch = None
2019 for fn in files:
2020 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
2021 foundpatch = fn
2022 if not foundpatch:
2023 self.fail('No patch file created next to bbappend')
2024 files.remove(foundpatch)
2025 if files:
2026 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
2027
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002028 def test_devtool_rename(self):
2029 # Check preconditions
2030 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
2031 self.track_for_cleanup(self.workspacedir)
2032 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
2033
2034 # First run devtool add
2035 # We already have this recipe in OE-Core, but that doesn't matter
2036 recipename = 'i2c-tools'
2037 recipever = '3.1.2'
2038 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
2039 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
2040 def add_recipe():
2041 result = runCmd('devtool add %s' % url)
2042 self.assertExists(recipefile, 'Expected recipe file not created')
2043 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
2044 checkvars = {}
2045 checkvars['S'] = None
2046 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2047 self._test_recipe_contents(recipefile, checkvars, [])
2048 add_recipe()
2049 # Now rename it - change both name and version
2050 newrecipename = 'mynewrecipe'
2051 newrecipever = '456'
2052 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
2053 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
2054 self.assertExists(newrecipefile, 'Recipe file not renamed')
2055 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2056 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
2057 self.assertExists(newsrctree, 'Source directory not renamed')
2058 checkvars = {}
2059 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
2060 checkvars['SRC_URI'] = url
2061 self._test_recipe_contents(newrecipefile, checkvars, [])
2062 # Try again - change just name this time
2063 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002064 add_recipe()
2065 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
2066 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
2067 self.assertExists(newrecipefile, 'Recipe file not renamed')
2068 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2069 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
2070 checkvars = {}
2071 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
2072 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2073 self._test_recipe_contents(newrecipefile, checkvars, [])
2074 # Try again - change just version this time
2075 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002076 add_recipe()
2077 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
2078 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
2079 self.assertExists(newrecipefile, 'Recipe file not renamed')
2080 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
2081 checkvars = {}
2082 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
2083 checkvars['SRC_URI'] = url
2084 self._test_recipe_contents(newrecipefile, checkvars, [])
2085
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002086 def test_devtool_virtual_kernel_modify(self):
2087 """
2088 Summary: The purpose of this test case is to verify that
2089 devtool modify works correctly when building
2090 the kernel.
2091 Dependencies: NA
2092 Steps: 1. Build kernel with bitbake.
2093 2. Save the config file generated.
2094 3. Clean the environment.
2095 4. Use `devtool modify virtual/kernel` to validate following:
2096 4.1 The source is checked out correctly.
2097 4.2 The resulting configuration is the same as
2098 what was get on step 2.
2099 4.3 The Kernel can be build correctly.
2100 4.4 Changes made on the source are reflected on the
2101 subsequent builds.
2102 4.5 Changes on the configuration are reflected on the
2103 subsequent builds
2104 Expected: devtool modify is able to checkout the source of the kernel
2105 and modification to the source and configurations are reflected
2106 when building the kernel.
Patrick Williams45852732022-04-02 08:58:32 -05002107 """
2108 kernel_provider = self.td['PREFERRED_PROVIDER_virtual/kernel']
2109
Andrew Geissler82c905d2020-04-13 13:39:40 -05002110 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002111 bitbake('%s -c clean' % kernel_provider)
2112 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2113 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
2114 self.track_for_cleanup(tempdir)
2115 self.track_for_cleanup(tempdir_cfg)
2116 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002117 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04002118 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002119 #Step 1
2120 #Here is just generated the config file instead of all the kernel to optimize the
2121 #time of executing this test case.
2122 bitbake('%s -c configure' % kernel_provider)
2123 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
2124 #Step 2
2125 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
2126 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
2127
2128 tmpconfig = os.path.join(tempdir_cfg, '.config')
2129 #Step 3
2130 bitbake('%s -c clean' % kernel_provider)
2131 #Step 4.1
2132 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
2133 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2134 #Step 4.2
2135 configfile = os.path.join(tempdir,'.config')
Patrick Williams45852732022-04-02 08:58:32 -05002136 runCmd('diff %s %s' % (tmpconfig, configfile))
2137
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002138 #Step 4.3
2139 #NOTE: virtual/kernel is mapped to kernel_provider
Patrick Williams45852732022-04-02 08:58:32 -05002140 runCmd('devtool build %s' % kernel_provider)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002141 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
2142 self.assertExists(kernelfile, 'Kernel was not build correctly')
2143
2144 #Modify the kernel source
Patrick Williams45852732022-04-02 08:58:32 -05002145 modfile = os.path.join(tempdir, 'init/version.c')
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002146 # Moved to uts.h in 6.1 onwards
2147 modfile2 = os.path.join(tempdir, 'include/linux/uts.h')
2148 runCmd("sed -i 's/Linux/LiNuX/g' %s %s" % (modfile, modfile2))
Patrick Williams45852732022-04-02 08:58:32 -05002149
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002150 #Modify the configuration
Patrick Williams45852732022-04-02 08:58:32 -05002151 codeconfigfile = os.path.join(tempdir, '.config.new')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002152 modconfopt = "CONFIG_SG_POOL=n"
Patrick Williams45852732022-04-02 08:58:32 -05002153 runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
2154
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002155 #Build again kernel with devtool
Patrick Williams45852732022-04-02 08:58:32 -05002156 runCmd('devtool build %s' % kernel_provider)
2157
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002158 #Step 4.4
Patrick Williams45852732022-04-02 08:58:32 -05002159 runCmd("grep '%s' %s" % ('LiNuX', kernelfile))
2160
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002161 #Step 4.5
Patrick Williams45852732022-04-02 08:58:32 -05002162 runCmd("grep %s %s" % (modconfopt, codeconfigfile))