blob: 94873fd19f41f14c67026d37dc7a29e049e33128 [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
13
Brad Bishopd7bf8c12018-02-25 22:55:05 -050014from oeqa.selftest.case import OESelftestTestCase
15from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer
16from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer
Patrick Williams45852732022-04-02 08:58:32 -050017from oeqa.core.decorator import OETestTag
Brad Bishopd7bf8c12018-02-25 22:55:05 -050018
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080019oldmetapath = None
20
21def setUpModule():
22 import bb.utils
23
24 global templayerdir
25 templayerdir = tempfile.mkdtemp(prefix='devtoolqa')
26 corecopydir = os.path.join(templayerdir, 'core-copy')
27 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
28 edited_layers = []
29
30 # We need to take a copy of the meta layer so we can modify it and not
31 # have any races against other tests that might be running in parallel
32 # however things like COREBASE mean that you can't just copy meta, you
33 # need the whole repository.
34 def bblayers_edit_cb(layerpath, canonical_layerpath):
35 global oldmetapath
36 if not canonical_layerpath.endswith('/'):
37 # This helps us match exactly when we're using this path later
38 canonical_layerpath += '/'
39 if not edited_layers and canonical_layerpath.endswith('/meta/'):
40 canonical_layerpath = os.path.realpath(canonical_layerpath) + '/'
41 edited_layers.append(layerpath)
42 oldmetapath = os.path.realpath(layerpath)
43 result = runCmd('git rev-parse --show-toplevel', cwd=canonical_layerpath)
44 oldreporoot = result.output.rstrip()
45 newmetapath = os.path.join(corecopydir, os.path.relpath(oldmetapath, oldreporoot))
46 runCmd('git clone %s %s' % (oldreporoot, corecopydir), cwd=templayerdir)
47 # Now we need to copy any modified files
48 # You might ask "why not just copy the entire tree instead of
49 # cloning and doing this?" - well, the problem with that is
50 # TMPDIR or an equally large subdirectory might exist
51 # under COREBASE and we don't want to copy that, so we have
52 # to be selective.
53 result = runCmd('git status --porcelain', cwd=oldreporoot)
54 for line in result.output.splitlines():
55 if line.startswith(' M ') or line.startswith('?? '):
56 relpth = line.split()[1]
57 pth = os.path.join(oldreporoot, relpth)
58 if pth.startswith(canonical_layerpath):
59 if relpth.endswith('/'):
60 destdir = os.path.join(corecopydir, relpth)
Andrew Geisslerc3d88e42020-10-02 09:45:00 -050061 # avoid race condition by not copying .pyc files YPBZ#13421,13803
Andrew Geisslerd1e89492021-02-12 15:35:20 -060062 shutil.copytree(pth, destdir, ignore=shutil.ignore_patterns('*.pyc', '__pycache__'))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080063 else:
64 destdir = os.path.join(corecopydir, os.path.dirname(relpth))
65 bb.utils.mkdirhier(destdir)
66 shutil.copy2(pth, destdir)
67 return newmetapath
68 else:
69 return layerpath
70 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
71
72def tearDownModule():
73 if oldmetapath:
74 edited_layers = []
75 def bblayers_edit_cb(layerpath, canonical_layerpath):
76 if not edited_layers and canonical_layerpath.endswith('/meta'):
77 edited_layers.append(layerpath)
78 return oldmetapath
79 else:
80 return layerpath
81 bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
82 bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
83 shutil.rmtree(templayerdir)
84
Andrew Geissler595f6302022-01-24 19:11:47 +000085class DevtoolTestCase(OESelftestTestCase):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080086
87 def setUp(self):
88 """Test case setup function"""
Andrew Geissler595f6302022-01-24 19:11:47 +000089 super(DevtoolTestCase, self).setUp()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080090 self.workspacedir = os.path.join(self.builddir, 'workspace')
91 self.assertTrue(not os.path.exists(self.workspacedir),
92 'This test cannot be run with a workspace directory '
93 'under the build directory')
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080094
95 def _check_src_repo(self, repo_dir):
96 """Check srctree git repository"""
97 self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')),
98 'git repository for external source tree not found')
99 result = runCmd('git status --porcelain', cwd=repo_dir)
100 self.assertEqual(result.output.strip(), "",
101 'Created git repo is not clean')
102 result = runCmd('git symbolic-ref HEAD', cwd=repo_dir)
103 self.assertEqual(result.output.strip(), "refs/heads/devtool",
104 'Wrong branch in git repo')
105
106 def _check_repo_status(self, repo_dir, expected_status):
107 """Check the worktree status of a repository"""
108 result = runCmd('git status . --porcelain',
109 cwd=repo_dir)
110 for line in result.output.splitlines():
111 for ind, (f_status, fn_re) in enumerate(expected_status):
112 if re.match(fn_re, line[3:]):
113 if f_status != line[:2]:
114 self.fail('Unexpected status in line: %s' % line)
115 expected_status.pop(ind)
116 break
117 else:
118 self.fail('Unexpected modified file in line: %s' % line)
119 if expected_status:
120 self.fail('Missing file changes: %s' % expected_status)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500121
122 def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
123 with open(recipefile, 'r') as f:
124 invar = None
125 invalue = None
Brad Bishop6dbb3162019-11-25 09:41:34 -0500126 inherits = set()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500127 for line in f:
128 var = None
129 if invar:
130 value = line.strip().strip('"')
131 if value.endswith('\\'):
132 invalue += ' ' + value[:-1].strip()
133 continue
134 else:
135 invalue += ' ' + value.strip()
136 var = invar
137 value = invalue
138 invar = None
139 elif '=' in line:
140 splitline = line.split('=', 1)
141 var = splitline[0].rstrip()
142 value = splitline[1].strip().strip('"')
143 if value.endswith('\\'):
144 invalue = value[:-1].strip()
145 invar = var
146 continue
147 elif line.startswith('inherit '):
Brad Bishop6dbb3162019-11-25 09:41:34 -0500148 inherits.update(line.split()[1:])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500149
150 if var and var in checkvars:
151 needvalue = checkvars.pop(var)
152 if needvalue is None:
153 self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value))
154 if isinstance(needvalue, set):
155 if var == 'LICENSE':
156 value = set(value.split(' & '))
157 else:
158 value = set(value.split())
159 self.assertEqual(value, needvalue, 'values for %s do not match' % var)
160
161
162 missingvars = {}
163 for var, value in checkvars.items():
164 if value is not None:
165 missingvars[var] = value
166 self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars)
167
168 for inherit in checkinherits:
169 self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
170
171 def _check_bbappend(self, testrecipe, recipefile, appenddir):
172 result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
173 resultlines = result.output.splitlines()
174 inrecipe = False
175 bbappends = []
176 bbappendfile = None
177 for line in resultlines:
178 if inrecipe:
179 if line.startswith(' '):
180 bbappends.append(line.strip())
181 else:
182 break
183 elif line == '%s:' % os.path.basename(recipefile):
184 inrecipe = True
185 self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
186 for bbappend in bbappends:
187 if bbappend.startswith(appenddir):
188 bbappendfile = bbappend
189 break
190 else:
191 self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
192 return bbappendfile
193
194 def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
195 create_temp_layer(templayerdir, templayername, priority, recipepathspec)
196 if addlayer:
197 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
198 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
199
200 def _process_ls_output(self, output):
201 """
202 Convert ls -l output to a format we can reasonably compare from one context
203 to another (e.g. from host to target)
204 """
205 filelist = []
206 for line in output.splitlines():
207 splitline = line.split()
208 if len(splitline) < 8:
209 self.fail('_process_ls_output: invalid output line: %s' % line)
210 # Remove trailing . on perms
211 splitline[0] = splitline[0].rstrip('.')
212 # Remove leading . on paths
213 splitline[-1] = splitline[-1].lstrip('.')
214 # Drop fields we don't want to compare
215 del splitline[7]
216 del splitline[6]
217 del splitline[5]
218 del splitline[4]
219 del splitline[1]
220 filelist.append(' '.join(splitline))
221 return filelist
222
Andrew Geissler615f2f12022-07-15 14:00:58 -0500223 def _check_diff(self, diffoutput, addlines, removelines):
224 """Check output from 'git diff' matches expectation"""
225 remaining_addlines = addlines[:]
226 remaining_removelines = removelines[:]
227 for line in diffoutput.splitlines():
228 if line.startswith('+++') or line.startswith('---'):
229 continue
230 elif line.startswith('+'):
231 matched = False
232 for item in addlines:
233 if re.match(item, line[1:].strip()):
234 matched = True
235 remaining_addlines.remove(item)
236 break
237 self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
238 elif line.startswith('-'):
239 matched = False
240 for item in removelines:
241 if re.match(item, line[1:].strip()):
242 matched = True
243 remaining_removelines.remove(item)
244 break
245 self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
246 if remaining_addlines:
247 self.fail('Expected added lines not found: %s' % remaining_addlines)
248 if remaining_removelines:
249 self.fail('Expected removed lines not found: %s' % remaining_removelines)
250
Patrick Williams92b42cb2022-09-03 06:53:57 -0500251 def _test_devtool_add_git_url(self, git_url, version, pn, resulting_src_uri):
252 self.track_for_cleanup(self.workspacedir)
253 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
254 result = runCmd('devtool add --version %s %s %s' % (version, pn, git_url))
255 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
256 # Check the recipe name is correct
257 recipefile = get_bb_var('FILE', pn)
258 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
259 self.assertIn(recipefile, result.output)
260 # Test devtool status
261 result = runCmd('devtool status')
262 self.assertIn(pn, result.output)
263 self.assertIn(recipefile, result.output)
264 checkvars = {}
265 checkvars['SRC_URI'] = resulting_src_uri
266 self._test_recipe_contents(recipefile, checkvars, [])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500267
Andrew Geissler595f6302022-01-24 19:11:47 +0000268class DevtoolBase(DevtoolTestCase):
269
270 @classmethod
271 def setUpClass(cls):
272 super(DevtoolBase, cls).setUpClass()
273 bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
274 cls.original_sstate = bb_vars['SSTATE_DIR']
275 cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
276 cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
277 cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
278 % cls.original_sstate)
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500279 cls.sstate_conf += ('BB_HASHSERVE_UPSTREAM = "hashserv.yocto.io:8687"\n')
Andrew Geissler595f6302022-01-24 19:11:47 +0000280
281 @classmethod
282 def tearDownClass(cls):
283 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
284 runCmd('rm -rf %s' % cls.devtool_sstate)
285 super(DevtoolBase, cls).tearDownClass()
286
287 def setUp(self):
288 """Test case setup function"""
289 super(DevtoolBase, self).setUp()
290 self.append_config(self.sstate_conf)
291
292
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500293class DevtoolTests(DevtoolBase):
294
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500295 def test_create_workspace(self):
296 # Check preconditions
297 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400298 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 -0400299 # remove conf/devtool.conf to avoid it corrupting tests
300 devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
301 self.track_for_cleanup(devtoolconf)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500302 # Try creating a workspace layer with a specific path
303 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
304 self.track_for_cleanup(tempdir)
305 result = runCmd('devtool create-workspace %s' % tempdir)
306 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
307 result = runCmd('bitbake-layers show-layers')
308 self.assertIn(tempdir, result.output)
309 # Try creating a workspace layer with the default path
310 self.track_for_cleanup(self.workspacedir)
311 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
312 result = runCmd('devtool create-workspace')
313 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
314 result = runCmd('bitbake-layers show-layers')
315 self.assertNotIn(tempdir, result.output)
316 self.assertIn(self.workspacedir, result.output)
317
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800318class DevtoolAddTests(DevtoolBase):
319
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500320 def test_devtool_add(self):
321 # Fetch source
322 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
323 self.track_for_cleanup(tempdir)
324 pn = 'pv'
325 pv = '1.5.3'
Andrew Geissler09209ee2020-12-13 08:44:15 -0600326 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500327 result = runCmd('wget %s' % url, cwd=tempdir)
328 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
329 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
330 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
331 # Test devtool add
332 self.track_for_cleanup(self.workspacedir)
333 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
334 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
335 result = runCmd('devtool add %s %s' % (pn, srcdir))
336 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
337 # Test devtool status
338 result = runCmd('devtool status')
339 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
340 self.assertIn(recipepath, result.output)
341 self.assertIn(srcdir, result.output)
342 # Test devtool find-recipe
343 result = runCmd('devtool -q find-recipe %s' % pn)
344 self.assertEqual(recipepath, result.output.strip())
345 # Test devtool edit-recipe
346 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
347 self.assertEqual('123 %s' % recipepath, result.output.strip())
348 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
349 bitbake('%s -c cleansstate' % pn)
350 # Test devtool build
351 result = runCmd('devtool build %s' % pn)
352 bb_vars = get_bb_vars(['D', 'bindir'], pn)
353 installdir = bb_vars['D']
354 self.assertTrue(installdir, 'Could not query installdir variable')
355 bindir = bb_vars['bindir']
356 self.assertTrue(bindir, 'Could not query bindir variable')
357 if bindir[0] == '/':
358 bindir = bindir[1:]
359 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
360
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500361 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800362 # We need dbus built so that DEPENDS recognition works
363 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500364 # Fetch source from a remote URL, but do it outside of devtool
365 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
366 self.track_for_cleanup(tempdir)
367 pn = 'dbus-wait'
368 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
369 # We choose an https:// git URL here to check rewriting the URL works
370 url = 'https://git.yoctoproject.org/git/dbus-wait'
371 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
372 # instead of the directory name
373 result = runCmd('git clone %s noname' % url, cwd=tempdir)
374 srcdir = os.path.join(tempdir, 'noname')
375 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
376 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
377 # Test devtool add
378 self.track_for_cleanup(self.workspacedir)
379 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
380 # Don't specify a name since we should be able to auto-detect it
381 result = runCmd('devtool add %s' % srcdir)
382 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
383 # Check the recipe name is correct
384 recipefile = get_bb_var('FILE', pn)
385 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
386 self.assertIn(recipefile, result.output)
387 # Test devtool status
388 result = runCmd('devtool status')
389 self.assertIn(pn, result.output)
390 self.assertIn(srcdir, result.output)
391 self.assertIn(recipefile, result.output)
392 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000393 checkvars['LICENSE'] = 'GPL-2.0-only'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500394 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
395 checkvars['S'] = '${WORKDIR}/git'
396 checkvars['PV'] = '0.1+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000397 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500398 checkvars['SRCREV'] = srcrev
399 checkvars['DEPENDS'] = set(['dbus'])
400 self._test_recipe_contents(recipefile, checkvars, [])
401
Patrick Williams92b42cb2022-09-03 06:53:57 -0500402 def test_devtool_add_git_style1(self):
403 version = 'v3.1.0'
404 pn = 'mbedtls'
405 # this will trigger reformat_git_uri with branch parameter in url
406 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https'"
407 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https"
408 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
409
410 def test_devtool_add_git_style2(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;protocol=https'"
415 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;protocol=https;branch=master"
416 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
417
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500418 def test_devtool_add_library(self):
419 # Fetch source
420 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
421 self.track_for_cleanup(tempdir)
422 version = '1.1'
423 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
424 result = runCmd('wget %s' % url, cwd=tempdir)
425 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
426 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
427 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
428 # Test devtool add (and use -V so we test that too)
429 self.track_for_cleanup(self.workspacedir)
430 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
431 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
432 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
433 # Test devtool status
434 result = runCmd('devtool status')
435 self.assertIn('libftdi', result.output)
436 self.assertIn(srcdir, result.output)
437 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
438 bitbake('libftdi -c cleansstate')
439 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
440 # There's also the matter of it installing cmake files to a path we don't
441 # normally cover, which triggers the installed-vs-shipped QA test we have
442 # within do_package
443 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
444 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
445 with open(recipefile, 'a') as f:
Patrick Williams213cb262021-08-07 19:21:33 -0500446 f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500447 # We don't have the ability to pick up this dependency automatically yet...
448 f.write('\nDEPENDS += "libusb1"\n')
449 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
450 # Test devtool build
451 result = runCmd('devtool build libftdi')
452 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
453 staging_libdir = bb_vars['TESTLIBOUTPUT']
454 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
455 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)
456 # Test devtool reset
457 stampprefix = bb_vars['STAMP']
458 result = runCmd('devtool reset libftdi')
459 result = runCmd('devtool status')
460 self.assertNotIn('libftdi', result.output)
461 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
462 matches = glob.glob(stampprefix + '*')
463 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
464 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
465
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500466 def test_devtool_add_fetch(self):
467 # Fetch source
468 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
469 self.track_for_cleanup(tempdir)
470 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400471 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500472 testrecipe = 'python-markupsafe'
473 srcdir = os.path.join(tempdir, testrecipe)
474 # Test devtool add
475 self.track_for_cleanup(self.workspacedir)
476 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
477 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
478 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
479 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
480 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
481 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
482 # Test devtool status
483 result = runCmd('devtool status')
484 self.assertIn(testrecipe, result.output)
485 self.assertIn(srcdir, result.output)
486 # Check recipe
487 recipefile = get_bb_var('FILE', testrecipe)
488 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
489 checkvars = {}
490 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
491 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
492 self._test_recipe_contents(recipefile, checkvars, [])
493 # Try with version specified
494 result = runCmd('devtool reset -n %s' % testrecipe)
495 shutil.rmtree(srcdir)
496 fakever = '1.9'
497 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
498 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
499 # Test devtool status
500 result = runCmd('devtool status')
501 self.assertIn(testrecipe, result.output)
502 self.assertIn(srcdir, result.output)
503 # Check recipe
504 recipefile = get_bb_var('FILE', testrecipe)
505 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
506 checkvars = {}
507 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
508 checkvars['SRC_URI'] = url
509 self._test_recipe_contents(recipefile, checkvars, [])
Andrew Geissler615f2f12022-07-15 14:00:58 -0500510
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500511 def test_devtool_add_fetch_git(self):
512 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
513 self.track_for_cleanup(tempdir)
514 url = 'gitsm://git.yoctoproject.org/mraa'
Andrew Geissler595f6302022-01-24 19:11:47 +0000515 url_branch = '%s;branch=master' % url
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500516 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
517 testrecipe = 'mraa'
518 srcdir = os.path.join(tempdir, testrecipe)
519 # Test devtool add
520 self.track_for_cleanup(self.workspacedir)
521 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
522 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
523 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
524 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
525 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
526 # Test devtool status
527 result = runCmd('devtool status')
528 self.assertIn(testrecipe, result.output)
529 self.assertIn(srcdir, result.output)
530 # Check recipe
531 recipefile = get_bb_var('FILE', testrecipe)
532 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
533 checkvars = {}
534 checkvars['S'] = '${WORKDIR}/git'
535 checkvars['PV'] = '1.0+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000536 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500537 checkvars['SRCREV'] = '${AUTOREV}'
538 self._test_recipe_contents(recipefile, checkvars, [])
539 # Try with revision and version specified
540 result = runCmd('devtool reset -n %s' % testrecipe)
541 shutil.rmtree(srcdir)
542 url_rev = '%s;rev=%s' % (url, checkrev)
543 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
544 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
545 # Test devtool status
546 result = runCmd('devtool status')
547 self.assertIn(testrecipe, result.output)
548 self.assertIn(srcdir, result.output)
549 # Check recipe
550 recipefile = get_bb_var('FILE', testrecipe)
551 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
552 checkvars = {}
553 checkvars['S'] = '${WORKDIR}/git'
554 checkvars['PV'] = '1.5+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000555 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500556 checkvars['SRCREV'] = checkrev
557 self._test_recipe_contents(recipefile, checkvars, [])
558
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500559 def test_devtool_add_fetch_simple(self):
560 # Fetch source from a remote URL, auto-detecting name
561 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
562 self.track_for_cleanup(tempdir)
563 testver = '1.6.0'
564 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
565 testrecipe = 'pv'
566 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
567 # Test devtool add
568 self.track_for_cleanup(self.workspacedir)
569 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
570 result = runCmd('devtool add %s' % url)
571 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
572 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
573 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
574 # Test devtool status
575 result = runCmd('devtool status')
576 self.assertIn(testrecipe, result.output)
577 self.assertIn(srcdir, result.output)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500578 # Check recipedevtool add
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500579 recipefile = get_bb_var('FILE', testrecipe)
580 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
581 checkvars = {}
582 checkvars['S'] = None
583 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
584 self._test_recipe_contents(recipefile, checkvars, [])
585
Andrew Geissler82c905d2020-04-13 13:39:40 -0500586 def test_devtool_add_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600587 collections = get_bb_var('BBFILE_COLLECTIONS').split()
588 if "openembedded-layer" not in collections:
589 self.skipTest("Test needs meta-oe for nodejs")
590
Andrew Geissler82c905d2020-04-13 13:39:40 -0500591 pn = 'savoirfairelinux-node-server-example'
592 pv = '1.0.0'
593 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
594 # Test devtool add
595 self.track_for_cleanup(self.workspacedir)
596 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
597 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
598 result = runCmd('devtool add \'%s\'' % url)
599 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
600 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
601 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
602 # Test devtool status
603 result = runCmd('devtool status')
604 self.assertIn(pn, result.output)
605 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
606 bitbake('%s -c cleansstate' % pn)
607 # Test devtool build
608 result = runCmd('devtool build %s' % pn)
609
Andrew Geissler615f2f12022-07-15 14:00:58 -0500610 def test_devtool_add_python_egg_requires(self):
611 # Fetch source
612 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
613 self.track_for_cleanup(tempdir)
614 testver = '0.14.0'
615 url = 'https://files.pythonhosted.org/packages/e9/9e/25d59f5043cf763833b2581c8027fa92342c4cf8ee523b498ecdf460c16d/uvicorn-%s.tar.gz' % testver
616 testrecipe = 'python3-uvicorn'
617 srcdir = os.path.join(tempdir, testrecipe)
618 # Test devtool add
619 self.track_for_cleanup(self.workspacedir)
620 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
621 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
622
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800623class DevtoolModifyTests(DevtoolBase):
624
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500625 def test_devtool_modify(self):
626 import oe.path
627
628 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
629 self.track_for_cleanup(tempdir)
630 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500631 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400632 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500633 result = runCmd('devtool modify mdadm -x %s' % tempdir)
634 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
635 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
636 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
637 self.assertTrue(matches, 'bbappend not created %s' % result.output)
638
639 # Test devtool status
640 result = runCmd('devtool status')
641 self.assertIn('mdadm', result.output)
642 self.assertIn(tempdir, result.output)
643 self._check_src_repo(tempdir)
644
645 bitbake('mdadm -C unpack')
646
647 def check_line(checkfile, expected, message, present=True):
648 # Check for $expected, on a line on its own, in checkfile.
649 with open(checkfile, 'r') as f:
650 if present:
651 self.assertIn(expected + '\n', f, message)
652 else:
653 self.assertNotIn(expected + '\n', f, message)
654
655 modfile = os.path.join(tempdir, 'mdadm.8.in')
656 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
657 pkgd = bb_vars['PKGD']
658 self.assertTrue(pkgd, 'Could not query PKGD variable')
659 mandir = bb_vars['mandir']
660 self.assertTrue(mandir, 'Could not query mandir variable')
661 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
662
663 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
664 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
665
666 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
667 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
668
669 bitbake('mdadm -c package')
670 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
671
672 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
673 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
674
675 bitbake('mdadm -c package')
676 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
677
678 result = runCmd('devtool reset mdadm')
679 result = runCmd('devtool status')
680 self.assertNotIn('mdadm', result.output)
681
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500682 def test_devtool_buildclean(self):
683 def assertFile(path, *paths):
684 f = os.path.join(path, *paths)
685 self.assertExists(f)
686 def assertNoFile(path, *paths):
687 f = os.path.join(path, *paths)
688 self.assertNotExists(f)
689
690 # Clean up anything in the workdir/sysroot/sstate cache
691 bitbake('mdadm m4 -c cleansstate')
692 # Try modifying a recipe
693 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
694 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
695 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
696 self.track_for_cleanup(tempdir_mdadm)
697 self.track_for_cleanup(tempdir_m4)
698 self.track_for_cleanup(builddir_m4)
699 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500700 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400701 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500702 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
703 try:
704 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
705 runCmd('devtool modify m4 -x %s' % tempdir_m4)
706 assertNoFile(tempdir_mdadm, 'mdadm')
707 assertNoFile(builddir_m4, 'src/m4')
708 result = bitbake('m4 -e')
709 result = bitbake('mdadm m4 -c compile')
710 self.assertEqual(result.status, 0)
711 assertFile(tempdir_mdadm, 'mdadm')
712 assertFile(builddir_m4, 'src/m4')
713 # Check that buildclean task exists and does call make clean
714 bitbake('mdadm m4 -c buildclean')
715 assertNoFile(tempdir_mdadm, 'mdadm')
716 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400717 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500718 bitbake('mdadm m4 -c compile')
719 assertFile(tempdir_mdadm, 'mdadm')
720 assertFile(builddir_m4, 'src/m4')
721 bitbake('mdadm m4 -c clean')
722 # Check that buildclean task is run before clean for B == S
723 assertNoFile(tempdir_mdadm, 'mdadm')
724 # Check that buildclean task is not run before clean for B != S
725 assertFile(builddir_m4, 'src/m4')
726 finally:
727 self.delete_recipeinc('m4')
728
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500729 def test_devtool_modify_invalid(self):
730 # Try modifying some recipes
731 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
732 self.track_for_cleanup(tempdir)
733 self.track_for_cleanup(self.workspacedir)
734 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
735
Andrew Geissler5199d832021-09-24 16:47:35 -0500736 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500737 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
738 result = runCmd('bitbake-layers show-recipes gcc-source*')
739 for line in result.output.splitlines():
740 # just match those lines that contain a real target
741 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
742 if m:
743 testrecipes.append(m.group('recipe'))
744 for testrecipe in testrecipes:
745 # Check it's a valid recipe
746 bitbake('%s -e' % testrecipe)
747 # devtool extract should fail
748 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
749 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
750 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
751 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
752 # devtool modify should fail
753 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
754 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
755 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
756
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500757 def test_devtool_modify_native(self):
758 # Check preconditions
759 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
760 # Try modifying some recipes
761 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
762 self.track_for_cleanup(tempdir)
763 self.track_for_cleanup(self.workspacedir)
764 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
765
766 bbclassextended = False
767 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500768 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500769 for testrecipe in testrecipes:
770 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
771 if not bbclassextended:
772 bbclassextended = checkextend
773 if not inheritnative:
774 inheritnative = not checkextend
775 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
776 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
777 result = runCmd('devtool build %s' % testrecipe)
778 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
779 result = runCmd('devtool reset %s' % testrecipe)
780 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
781
782 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
783 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 -0500784
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600785 def test_devtool_modify_localfiles_only(self):
786 # Check preconditions
787 testrecipe = 'base-files'
788 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
789 foundlocalonly = False
790 correct_symlink = False
791 for item in src_uri:
792 if item.startswith('file://'):
793 if '.patch' not in item:
794 foundlocalonly = True
795 else:
796 foundlocalonly = False
797 break
798 self.assertTrue(foundlocalonly, 'This test expects the %s recipe to fetch local files only and it seems that it no longer does' % testrecipe)
799 # Clean up anything in the workdir/sysroot/sstate cache
800 bitbake('%s -c cleansstate' % testrecipe)
801 # Try modifying a recipe
802 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
803 self.track_for_cleanup(tempdir)
804 self.track_for_cleanup(self.workspacedir)
805 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
806 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
807 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
808 srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
809 srclink = os.path.join(tempdir, 'share/dot.bashrc')
810 self.assertExists(srcfile, 'Extracted source could not be found')
811 if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
812 correct_symlink = True
813 self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500814
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600815 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
816 self.assertTrue(matches, 'bbappend not created')
817 # Test devtool status
818 result = runCmd('devtool status')
819 self.assertIn(testrecipe, result.output)
820 self.assertIn(tempdir, result.output)
821 # Try building
822 bitbake(testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500823
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500824 def test_devtool_modify_git(self):
825 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400826 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500827 src_uri = get_bb_var('SRC_URI', testrecipe)
828 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
829 # Clean up anything in the workdir/sysroot/sstate cache
830 bitbake('%s -c cleansstate' % testrecipe)
831 # Try modifying a recipe
832 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
833 self.track_for_cleanup(tempdir)
834 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500835 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400836 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500837 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400838 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500839 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 -0400840 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500841 self.assertTrue(matches, 'bbappend not created')
842 # Test devtool status
843 result = runCmd('devtool status')
844 self.assertIn(testrecipe, result.output)
845 self.assertIn(tempdir, result.output)
846 # Check git repo
847 self._check_src_repo(tempdir)
848 # Try building
849 bitbake(testrecipe)
850
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500851 def test_devtool_modify_git_crates_subpath(self):
852 # This tests two things in devtool context:
853 # - that we support local git dependencies for cargo based recipe
854 # - that we support patches in SRC_URI when git url contains subpath parameter
855
856 # Check preconditions:
857 # recipe inherits cargo
858 # git:// uri with a subpath as the main package
859 # some crate:// in SRC_URI
860 # others git:// in SRC_URI
861 # cointains a patch
862 testrecipe = 'zvariant'
863 bb_vars = get_bb_vars(['SRC_URI', 'FILE', 'WORKDIR', 'CARGO_HOME'], testrecipe)
864 recipefile = bb_vars['FILE']
865 workdir = bb_vars['WORKDIR']
866 cargo_home = bb_vars['CARGO_HOME']
867 src_uri = bb_vars['SRC_URI'].split()
868 self.assertTrue(src_uri[0].startswith('git://'),
869 'This test expects the %s recipe to have a git repo has its main uri' % testrecipe)
870 self.assertIn(';subpath=', src_uri[0],
871 'This test expects the %s recipe to have a git uri with subpath' % testrecipe)
872 self.assertTrue(any([uri.startswith('crate://') for uri in src_uri]),
873 'This test expects the %s recipe to have some crates in its src uris' % testrecipe)
874 self.assertGreater(sum(map(lambda x:x.startswith('git://'), src_uri)), 2,
875 'This test expects the %s recipe to have several git:// uris' % testrecipe)
876 self.assertTrue(any([uri.startswith('file://') and '.patch' in uri for uri in src_uri]),
877 'This test expects the %s recipe to have a patch in its src uris' % testrecipe)
878
879 self._test_recipe_contents(recipefile, {}, ['cargo'])
880
881 # Clean up anything in the workdir/sysroot/sstate cache
882 bitbake('%s -c cleansstate' % testrecipe)
883 # Try modifying a recipe
884 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
885 self.track_for_cleanup(tempdir)
886 self.track_for_cleanup(self.workspacedir)
887 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
888 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
889 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
890 self.assertExists(os.path.join(tempdir, 'Cargo.toml'), 'Extracted source could not be found')
891 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
892 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'zvariant_*.bbappend'))
893 self.assertTrue(matches, 'bbappend not created')
894 # Test devtool status
895 result = runCmd('devtool status')
896 self.assertIn(testrecipe, result.output)
897 self.assertIn(tempdir, result.output)
898 # Check git repo
899 self._check_src_repo(tempdir)
900 # Check that the patch is correctly applied
901 # last commit message in the tree must contain
902 # %% original patch: <patchname>
903 # ..
904 patchname = None
905 for uri in src_uri:
906 if uri.startswith('file://') and '.patch' in uri:
907 patchname = uri.replace("file://", "").partition('.patch')[0] + '.patch'
908 self.assertIsNotNone(patchname)
909 result = runCmd('git -C %s log -1' % tempdir)
910 self.assertIn("%%%% original patch: %s" % patchname, result.output)
911
912 # Configure the recipe to check that the git dependencies are correctly patched in cargo config
913 bitbake('-c configure %s' % testrecipe)
914
915 cargo_config_path = os.path.join(cargo_home, 'config')
916 with open(cargo_config_path, "r") as f:
917 cargo_config_contents = [line.strip('\n') for line in f.readlines()]
918
919 # Get back git dependencies of the recipe (ignoring the main one)
920 # and check that they are all correctly patched to be fetched locally
921 git_deps = [uri for uri in src_uri if uri.startswith("git://")][1:]
922 for git_dep in git_deps:
923 raw_url, _, raw_parms = git_dep.partition(";")
924 parms = {}
925 for parm in raw_parms.split(";"):
926 name_parm, _, value_parm = parm.partition('=')
927 parms[name_parm]=value_parm
928 self.assertIn('protocol', parms, 'git dependencies uri should contain the "protocol" parameter')
929 self.assertIn('name', parms, 'git dependencies uri should contain the "name" parameter')
930 self.assertIn('destsuffix', parms, 'git dependencies uri should contain the "destsuffix" parameter')
931 self.assertIn('type', parms, 'git dependencies uri should contain the "type" parameter')
932 self.assertEqual(parms['type'], 'git-dependency', 'git dependencies uri should have "type=git-dependency"')
933 raw_url = raw_url.replace("git://", '%s://' % parms['protocol'])
934 patch_line = '[patch."%s"]' % raw_url
935 path_patched = os.path.join(workdir, parms['destsuffix'])
936 path_override_line = '%s = { path = "%s" }' % (parms['name'], path_patched)
937 # Would have been better to use tomllib to read this file :/
938 self.assertIn(patch_line, cargo_config_contents)
939 self.assertIn(path_override_line, cargo_config_contents)
940
941 # Try to package the recipe
942 bitbake('-c package_qa %s' % testrecipe)
943
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500944 def test_devtool_modify_localfiles(self):
945 # Check preconditions
946 testrecipe = 'lighttpd'
947 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
948 foundlocal = False
949 for item in src_uri:
950 if item.startswith('file://') and '.patch' not in item:
951 foundlocal = True
952 break
953 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
954 # Clean up anything in the workdir/sysroot/sstate cache
955 bitbake('%s -c cleansstate' % testrecipe)
956 # Try modifying a recipe
957 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
958 self.track_for_cleanup(tempdir)
959 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500960 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400961 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500962 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
963 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
964 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
965 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
966 self.assertTrue(matches, 'bbappend not created')
967 # Test devtool status
968 result = runCmd('devtool status')
969 self.assertIn(testrecipe, result.output)
970 self.assertIn(tempdir, result.output)
971 # Try building
972 bitbake(testrecipe)
973
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500974 def test_devtool_modify_virtual(self):
975 # Try modifying a virtual recipe
976 virtrecipe = 'virtual/make'
977 realrecipe = 'make'
978 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
979 self.track_for_cleanup(tempdir)
980 self.track_for_cleanup(self.workspacedir)
981 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
982 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
983 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
984 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
985 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
986 self.assertTrue(matches, 'bbappend not created %s' % result.output)
987 # Test devtool status
988 result = runCmd('devtool status')
989 self.assertNotIn(virtrecipe, result.output)
990 self.assertIn(realrecipe, result.output)
991 # Check git repo
992 self._check_src_repo(tempdir)
993 # This is probably sufficient
994
Andrew Geisslerf0343792020-11-18 10:42:21 -0600995 def test_devtool_modify_overrides(self):
996 # Try modifying a recipe with patches in overrides
997 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
998 self.track_for_cleanup(tempdir)
999 self.track_for_cleanup(self.workspacedir)
1000 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1001 result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
1002
1003 self._check_src_repo(tempdir)
1004 source = os.path.join(tempdir, "source")
1005 def check(branch, expected):
1006 runCmd('git -C %s checkout %s' % (tempdir, branch))
1007 with open(source, "rt") as f:
1008 content = f.read()
1009 self.assertEquals(content, expected)
1010 check('devtool', 'This is a test for something\n')
1011 check('devtool-no-overrides', 'This is a test for something\n')
1012 check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
1013 check('devtool-override-qemux86', 'This is a test for qemux86\n')
1014
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001015class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001016
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001017 def test_devtool_update_recipe(self):
1018 # Check preconditions
1019 testrecipe = 'minicom'
1020 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1021 recipefile = bb_vars['FILE']
1022 src_uri = bb_vars['SRC_URI']
1023 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1024 self._check_repo_status(os.path.dirname(recipefile), [])
1025 # First, modify a recipe
1026 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1027 self.track_for_cleanup(tempdir)
1028 self.track_for_cleanup(self.workspacedir)
1029 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1030 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1031 # We don't use -x here so that we test the behaviour of devtool modify without it
1032 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
1033 # Check git repo
1034 self._check_src_repo(tempdir)
1035 # Add a couple of commits
1036 # FIXME: this only tests adding, need to also test update and remove
1037 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
1038 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
1039 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1040 result = runCmd('git add devtool-new-file', cwd=tempdir)
1041 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1042 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1043 result = runCmd('devtool update-recipe %s' % testrecipe)
1044 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1045 ('??', '.*/0001-Change-the-README.patch$'),
1046 ('??', '.*/0002-Add-a-new-file.patch$')]
1047 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1048
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001049 def test_devtool_update_recipe_git(self):
1050 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001051 testrecipe = 'mtd-utils-selftest'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001052 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1053 recipefile = bb_vars['FILE']
1054 src_uri = bb_vars['SRC_URI']
1055 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1056 patches = []
1057 for entry in src_uri.split():
1058 if entry.startswith('file://') and entry.endswith('.patch'):
1059 patches.append(entry[7:].split(';')[0])
1060 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
1061 self._check_repo_status(os.path.dirname(recipefile), [])
1062 # First, modify a recipe
1063 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1064 self.track_for_cleanup(tempdir)
1065 self.track_for_cleanup(self.workspacedir)
1066 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1067 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1068 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1069 # Check git repo
1070 self._check_src_repo(tempdir)
1071 # Add a couple of commits
1072 # FIXME: this only tests adding, need to also test update and remove
1073 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
1074 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
1075 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
1076 result = runCmd('git add devtool-new-file', cwd=tempdir)
1077 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
1078 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1079 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
1080 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
1081 [(' D', '.*/%s$' % patch) for patch in patches]
1082 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1083
1084 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +00001085 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001086 srcurilines = src_uri.split()
1087 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
1088 srcurilines.append('"')
1089 removelines = ['SRCREV = ".*"'] + srcurilines
Andrew Geissler615f2f12022-07-15 14:00:58 -05001090 self._check_diff(result.output, addlines, removelines)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001091 # Now try with auto mode
1092 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
1093 result = runCmd('devtool update-recipe %s' % testrecipe)
1094 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
1095 topleveldir = result.output.strip()
1096 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
1097 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
1098 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
1099 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
1100 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1101
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001102 def test_devtool_update_recipe_append(self):
1103 # Check preconditions
1104 testrecipe = 'mdadm'
1105 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1106 recipefile = bb_vars['FILE']
1107 src_uri = bb_vars['SRC_URI']
1108 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1109 self._check_repo_status(os.path.dirname(recipefile), [])
1110 # First, modify a recipe
1111 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1112 tempsrcdir = os.path.join(tempdir, 'source')
1113 templayerdir = os.path.join(tempdir, 'layer')
1114 self.track_for_cleanup(tempdir)
1115 self.track_for_cleanup(self.workspacedir)
1116 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1117 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1118 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1119 # Check git repo
1120 self._check_src_repo(tempsrcdir)
1121 # Add a commit
1122 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
1123 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1124 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1125 # Create a temporary layer and add it to bblayers.conf
1126 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
1127 # Create the bbappend
1128 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1129 self.assertNotIn('WARNING:', result.output)
1130 # Check recipe is still clean
1131 self._check_repo_status(os.path.dirname(recipefile), [])
1132 # Check bbappend was created
1133 splitpath = os.path.dirname(recipefile).split(os.sep)
1134 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1135 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1136 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
1137 self.assertExists(patchfile, 'Patch file not created')
1138
1139 # Check bbappend contents
Patrick Williams213cb262021-08-07 19:21:33 -05001140 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001141 '\n',
1142 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
1143 '\n']
1144 with open(bbappendfile, 'r') as f:
1145 self.assertEqual(expectedlines, f.readlines())
1146
1147 # Check we can run it again and bbappend isn't modified
1148 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1149 with open(bbappendfile, 'r') as f:
1150 self.assertEqual(expectedlines, f.readlines())
1151 # Drop new commit and check patch gets deleted
1152 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1153 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1154 self.assertNotExists(patchfile, 'Patch file not deleted')
Patrick Williams213cb262021-08-07 19:21:33 -05001155 expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001156 '\n']
1157 with open(bbappendfile, 'r') as f:
1158 self.assertEqual(expectedlines2, f.readlines())
1159 # Put commit back and check we can run it if layer isn't in bblayers.conf
1160 os.remove(bbappendfile)
1161 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1162 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1163 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1164 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1165 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
1166 with open(bbappendfile, 'r') as f:
1167 self.assertEqual(expectedlines, f.readlines())
1168 # Deleting isn't expected to work under these circumstances
1169
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001170 def test_devtool_update_recipe_append_git(self):
1171 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001172 testrecipe = 'mtd-utils-selftest'
Andrew Geissler517393d2023-01-13 08:55:19 -06001173 bb_vars = get_bb_vars(['FILE', 'SRC_URI', 'LAYERSERIES_CORENAMES'], testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001174 recipefile = bb_vars['FILE']
1175 src_uri = bb_vars['SRC_URI']
Andrew Geissler517393d2023-01-13 08:55:19 -06001176 corenames = bb_vars['LAYERSERIES_CORENAMES']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001177 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1178 for entry in src_uri.split():
1179 if entry.startswith('git://'):
1180 git_uri = entry
1181 break
1182 self._check_repo_status(os.path.dirname(recipefile), [])
1183 # First, modify a recipe
1184 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1185 tempsrcdir = os.path.join(tempdir, 'source')
1186 templayerdir = os.path.join(tempdir, 'layer')
1187 self.track_for_cleanup(tempdir)
1188 self.track_for_cleanup(self.workspacedir)
1189 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1190 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1191 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1192 # Check git repo
1193 self._check_src_repo(tempsrcdir)
1194 # Add a commit
1195 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
1196 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1197 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1198 # Create a temporary layer
1199 os.makedirs(os.path.join(templayerdir, 'conf'))
1200 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
1201 f.write('BBPATH .= ":${LAYERDIR}"\n')
1202 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
1203 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
1204 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
1205 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
1206 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Andrew Geissler517393d2023-01-13 08:55:19 -06001207 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "%s"\n' % corenames)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001208 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
1209 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
1210 # Create the bbappend
1211 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1212 self.assertNotIn('WARNING:', result.output)
1213 # Check recipe is still clean
1214 self._check_repo_status(os.path.dirname(recipefile), [])
1215 # Check bbappend was created
1216 splitpath = os.path.dirname(recipefile).split(os.sep)
1217 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1218 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1219 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1220
1221 # Check bbappend contents
1222 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1223 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1224 '\n',
1225 'SRC_URI = "%s"\n' % git_uri,
1226 '\n'])
1227 with open(bbappendfile, 'r') as f:
1228 self.assertEqual(expectedlines, set(f.readlines()))
1229
1230 # Check we can run it again and bbappend isn't modified
1231 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1232 with open(bbappendfile, 'r') as f:
1233 self.assertEqual(expectedlines, set(f.readlines()))
1234 # Drop new commit and check SRCREV changes
1235 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1236 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1237 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1238 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1239 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1240 '\n',
1241 'SRC_URI = "%s"\n' % git_uri,
1242 '\n'])
1243 with open(bbappendfile, 'r') as f:
1244 self.assertEqual(expectedlines, set(f.readlines()))
1245 # Put commit back and check we can run it if layer isn't in bblayers.conf
1246 os.remove(bbappendfile)
1247 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1248 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1249 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1250 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1251 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1252 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1253 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1254 '\n',
1255 'SRC_URI = "%s"\n' % git_uri,
1256 '\n'])
1257 with open(bbappendfile, 'r') as f:
1258 self.assertEqual(expectedlines, set(f.readlines()))
1259 # Deleting isn't expected to work under these circumstances
1260
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001261 def test_devtool_update_recipe_local_files(self):
1262 """Check that local source files are copied over instead of patched"""
1263 testrecipe = 'makedevs'
1264 recipefile = get_bb_var('FILE', testrecipe)
1265 # Setup srctree for modifying the recipe
1266 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1267 self.track_for_cleanup(tempdir)
1268 self.track_for_cleanup(self.workspacedir)
1269 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1270 # (don't bother with cleaning the recipe on teardown, we won't be
1271 # building it)
1272 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1273 # Check git repo
1274 self._check_src_repo(tempdir)
1275 # Try building just to ensure we haven't broken that
1276 bitbake("%s" % testrecipe)
1277 # Edit / commit local source
1278 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1279 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1280 runCmd('echo "Bar" > new-file', cwd=tempdir)
1281 runCmd('git add new-file', cwd=tempdir)
1282 runCmd('git commit -m "Add new file"', cwd=tempdir)
1283 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1284 os.path.dirname(recipefile))
1285 runCmd('devtool update-recipe %s' % testrecipe)
1286 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1287 (' M', '.*/makedevs/makedevs.c$'),
1288 ('??', '.*/makedevs/new-local$'),
1289 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1290 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1291
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001292 def test_devtool_update_recipe_local_files_2(self):
1293 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001294 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001295 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001296 recipedir = os.path.dirname(recipefile)
1297 result = runCmd('git status --porcelain .', cwd=recipedir)
1298 if result.output.strip():
1299 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001300 # Setup srctree for modifying the recipe
1301 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1302 self.track_for_cleanup(tempdir)
1303 self.track_for_cleanup(self.workspacedir)
1304 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1305 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1306 # Check git repo
1307 self._check_src_repo(tempdir)
1308 # Add oe-local-files to Git
1309 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1310 runCmd('git add oe-local-files', cwd=tempdir)
1311 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1312 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001313 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001314 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001315 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001316 runCmd('git commit -m"Remove file"', cwd=tempdir)
1317 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1318 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1319 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1320 runCmd('echo "Gar" > new-file', cwd=tempdir)
1321 runCmd('git add new-file', cwd=tempdir)
1322 runCmd('git commit -m "Add new file"', cwd=tempdir)
1323 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1324 os.path.dirname(recipefile))
1325 # Checkout unmodified file to working copy -> devtool should still pick
1326 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001327 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001328 runCmd('devtool update-recipe %s' % testrecipe)
1329 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001330 (' M', '.*/file1$'),
1331 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001332 ('??', '.*/new-local$'),
1333 ('??', '.*/0001-Add-new-file.patch$')]
1334 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1335
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001336 def test_devtool_update_recipe_with_gitignore(self):
1337 # First, modify the recipe
1338 testrecipe = 'devtool-test-ignored'
1339 bb_vars = get_bb_vars(['FILE'], testrecipe)
1340 recipefile = bb_vars['FILE']
1341 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1342 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
1343 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1344 self.track_for_cleanup(tempdir)
1345 self.track_for_cleanup(self.workspacedir)
1346 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1347 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1348 result = runCmd('devtool modify %s' % testrecipe)
1349 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1350 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1351 # Check recipe got changed as expected
1352 with open(newpatchfile, 'r') as f:
1353 desiredlines = f.readlines()
1354 with open(patchfile, 'r') as f:
1355 newlines = f.readlines()
1356 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1357 # which changes the metadata subject which is added into the patch, but keep
1358 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1359 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1360 self.assertEqual(desiredlines[5:], newlines[5:])
1361
1362 def test_devtool_update_recipe_long_filename(self):
1363 # First, modify the recipe
1364 testrecipe = 'devtool-test-long-filename'
1365 bb_vars = get_bb_vars(['FILE'], testrecipe)
1366 recipefile = bb_vars['FILE']
1367 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1368 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1369 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1370 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1371 self.track_for_cleanup(tempdir)
1372 self.track_for_cleanup(self.workspacedir)
1373 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1374 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1375 result = runCmd('devtool modify %s' % testrecipe)
1376 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1377 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1378 # Check recipe got changed as expected
1379 with open(newpatchfile, 'r') as f:
1380 desiredlines = f.readlines()
1381 with open(patchfile, 'r') as f:
1382 newlines = f.readlines()
1383 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1384 # which changes the metadata subject which is added into the patch, but keep
1385 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1386 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1387 self.assertEqual(desiredlines[5:], newlines[5:])
1388
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001389 def test_devtool_update_recipe_local_files_3(self):
1390 # First, modify the recipe
1391 testrecipe = 'devtool-test-localonly'
1392 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1393 recipefile = bb_vars['FILE']
1394 src_uri = bb_vars['SRC_URI']
1395 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1396 self.track_for_cleanup(tempdir)
1397 self.track_for_cleanup(self.workspacedir)
1398 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1399 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1400 result = runCmd('devtool modify %s' % testrecipe)
1401 # Modify one file
1402 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1403 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1404 result = runCmd('devtool update-recipe %s' % testrecipe)
1405 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1406 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1407
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001408 def test_devtool_update_recipe_local_patch_gz(self):
1409 # First, modify the recipe
1410 testrecipe = 'devtool-test-patch-gz'
1411 if get_bb_var('DISTRO') == 'poky-tiny':
1412 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1413 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1414 recipefile = bb_vars['FILE']
1415 src_uri = bb_vars['SRC_URI']
1416 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1417 self.track_for_cleanup(tempdir)
1418 self.track_for_cleanup(self.workspacedir)
1419 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1420 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1421 result = runCmd('devtool modify %s' % testrecipe)
1422 # Modify one file
1423 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1424 runCmd('echo "Another line" >> README', cwd=srctree)
1425 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1426 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1427 result = runCmd('devtool update-recipe %s' % testrecipe)
1428 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1429 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1430 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1431 result = runCmd('file %s' % patch_gz)
1432 if 'gzip compressed data' not in result.output:
1433 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1434
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001435 def test_devtool_update_recipe_local_files_subdir(self):
1436 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1437 # SRC_URI such that it overwrites a file that was in an archive that
1438 # was also in SRC_URI
1439 # First, modify the recipe
1440 testrecipe = 'devtool-test-subdir'
1441 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1442 recipefile = bb_vars['FILE']
1443 src_uri = bb_vars['SRC_URI']
1444 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1445 self.track_for_cleanup(tempdir)
1446 self.track_for_cleanup(self.workspacedir)
1447 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1448 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1449 result = runCmd('devtool modify %s' % testrecipe)
1450 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1451 self.assertExists(testfile, 'Extracted source could not be found')
1452 with open(testfile, 'r') as f:
1453 contents = f.read().rstrip()
1454 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1455 # Test devtool update-recipe without modifying any files
1456 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1457 result = runCmd('devtool update-recipe %s' % testrecipe)
1458 expected_status = []
1459 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1460
Andrew Geissler615f2f12022-07-15 14:00:58 -05001461 def test_devtool_finish_modify_git_subdir(self):
1462 # Check preconditions
1463 testrecipe = 'dos2unix'
1464 bb_vars = get_bb_vars(['SRC_URI', 'S', 'WORKDIR', 'FILE'], testrecipe)
1465 self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe)
1466 workdir_git = '%s/git/' % bb_vars['WORKDIR']
1467 if not bb_vars['S'].startswith(workdir_git):
1468 self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe)
1469 subdir = bb_vars['S'].split(workdir_git, 1)[1]
1470 # Clean up anything in the workdir/sysroot/sstate cache
1471 bitbake('%s -c cleansstate' % testrecipe)
1472 # Try modifying a recipe
1473 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1474 self.track_for_cleanup(tempdir)
1475 self.track_for_cleanup(self.workspacedir)
1476 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1477 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1478 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1479 testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c')
1480 self.assertExists(testsrcfile, 'Extracted source could not be found')
1481 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
1482 self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo')
1483 # Check git repo
1484 self._check_src_repo(tempdir)
1485 # Modify file
1486 runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile)
1487 result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir)
1488 # Now try updating original recipe
1489 recipefile = bb_vars['FILE']
1490 recipedir = os.path.dirname(recipefile)
1491 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1492 result = runCmd('devtool update-recipe %s' % testrecipe)
1493 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1494 ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))]
1495 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1496 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
1497 removelines = ['SRC_URI = "git://.*"']
1498 addlines = [
1499 'SRC_URI = "git://.* \\\\',
1500 'file://0001-Add-a-comment.patch;patchdir=.. \\\\',
1501 '"'
1502 ]
1503 self._check_diff(result.output, addlines, removelines)
1504 # Put things back so we can run devtool finish on a different layer
1505 runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1506 # Run devtool finish
1507 res = re.search('recipes-.*', recipedir)
1508 self.assertTrue(res, 'Unable to find recipe subdirectory')
1509 recipesubdir = res[0]
1510 self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir))
1511 result = runCmd('devtool finish %s meta-selftest' % testrecipe)
1512 # Check bbappend file contents
1513 appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe)
1514 with open(appendfn, 'r') as f:
1515 appendlines = f.readlines()
1516 expected_appendlines = [
1517 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
1518 '\n',
1519 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n',
1520 '\n'
1521 ]
1522 self.assertEqual(appendlines, expected_appendlines)
1523 self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch'))
1524 # Try building
1525 bitbake('%s -c patch' % testrecipe)
1526
1527
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001528class DevtoolExtractTests(DevtoolBase):
1529
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001530 def test_devtool_extract(self):
1531 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1532 # Try devtool extract
1533 self.track_for_cleanup(tempdir)
1534 self.track_for_cleanup(self.workspacedir)
1535 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1536 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1537 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1538 self._check_src_repo(tempdir)
1539
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001540 def test_devtool_extract_virtual(self):
1541 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1542 # Try devtool extract
1543 self.track_for_cleanup(tempdir)
1544 self.track_for_cleanup(self.workspacedir)
1545 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1546 result = runCmd('devtool extract virtual/make %s' % tempdir)
1547 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1548 self._check_src_repo(tempdir)
1549
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001550 def test_devtool_reset_all(self):
1551 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
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 testrecipe1 = 'mdadm'
1556 testrecipe2 = 'cronie'
1557 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1558 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1559 result = runCmd('devtool build %s' % testrecipe1)
1560 result = runCmd('devtool build %s' % testrecipe2)
1561 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1562 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1563 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1564 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1565 result = runCmd('devtool reset -a')
1566 self.assertIn(testrecipe1, result.output)
1567 self.assertIn(testrecipe2, result.output)
1568 result = runCmd('devtool status')
1569 self.assertNotIn(testrecipe1, result.output)
1570 self.assertNotIn(testrecipe2, result.output)
1571 matches1 = glob.glob(stampprefix1 + '*')
1572 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1573 matches2 = glob.glob(stampprefix2 + '*')
1574 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1575
Patrick Williams45852732022-04-02 08:58:32 -05001576 @OETestTag("runqemu")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001577 def test_devtool_deploy_target(self):
1578 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1579 # unfortunately the runtime tests run under bitbake and you can't run
1580 # devtool within bitbake (since devtool needs to run bitbake itself).
1581 # Additionally we are testing build-time functionality as well, so
1582 # really this has to be done as an oe-selftest test.
1583 #
1584 # Check preconditions
1585 machine = get_bb_var('MACHINE')
1586 if not machine.startswith('qemu'):
1587 self.skipTest('This test only works with qemu machines')
1588 if not os.path.exists('/etc/runqemu-nosudo'):
1589 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1590 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1591 if result.status != 0:
1592 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1593 if result.status != 0:
1594 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1595 for line in result.output.splitlines():
1596 if line.startswith('tap'):
1597 break
1598 else:
1599 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1600 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1601 # Definitions
1602 testrecipe = 'mdadm'
1603 testfile = '/sbin/mdadm'
1604 testimage = 'oe-selftest-image'
1605 testcommand = '/sbin/mdadm --help'
1606 # Build an image to run
1607 bitbake("%s qemu-native qemu-helper-native" % testimage)
1608 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1609 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1610 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1611 # Clean recipe so the first deploy will fail
1612 bitbake("%s -c clean" % testrecipe)
1613 # Try devtool modify
1614 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1615 self.track_for_cleanup(tempdir)
1616 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001617 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001618 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001619 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1620 # Test that deploy-target at this point fails (properly)
1621 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1622 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1623 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1624 result = runCmd('devtool build %s' % testrecipe)
1625 # First try a dry-run of deploy-target
1626 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1627 self.assertIn(' %s' % testfile, result.output)
1628 # Boot the image
1629 with runqemu(testimage) as qemu:
1630 # Now really test deploy-target
1631 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1632 # Run a test command to see if it was installed properly
1633 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1634 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1635 # Check if it deployed all of the files with the right ownership/perms
1636 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1637 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1638 installdir = bb_vars['D']
1639 fakerootenv = bb_vars['FAKEROOTENV']
1640 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001641 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001642 filelist1 = self._process_ls_output(result.output)
1643
1644 # Now look on the target
1645 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1646 self.track_for_cleanup(tempdir2)
1647 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1648 with open(tmpfilelist, 'w') as f:
1649 for line in filelist1:
1650 splitline = line.split()
1651 f.write(splitline[-1] + '\n')
1652 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1653 filelist2 = self._process_ls_output(result.output)
1654 filelist1.sort(key=lambda item: item.split()[-1])
1655 filelist2.sort(key=lambda item: item.split()[-1])
1656 self.assertEqual(filelist1, filelist2)
1657 # Test undeploy-target
1658 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1659 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1660 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1661
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001662 def test_devtool_build_image(self):
1663 """Test devtool build-image plugin"""
1664 # Check preconditions
1665 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1666 image = 'core-image-minimal'
1667 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001668 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001669 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001670 bitbake('%s -c clean' % image)
1671 # Add target and native recipes to workspace
1672 recipes = ['mdadm', 'parted-native']
1673 for recipe in recipes:
1674 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1675 self.track_for_cleanup(tempdir)
1676 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1677 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1678 # Try to build image
1679 result = runCmd('devtool build-image %s' % image)
1680 self.assertNotEqual(result, 0, 'devtool build-image failed')
1681 # Check if image contains expected packages
1682 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1683 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1684 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1685 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1686 for line in f:
1687 splitval = line.split()
1688 if splitval:
1689 pkg = splitval[0]
1690 if pkg in reqpkgs:
1691 reqpkgs.remove(pkg)
1692 if reqpkgs:
1693 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1694
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001695class DevtoolUpgradeTests(DevtoolBase):
1696
Patrick Williams45852732022-04-02 08:58:32 -05001697 def setUp(self):
1698 super().setUp()
1699 try:
1700 runCmd("git config --global user.name")
1701 runCmd("git config --global user.email")
1702 except:
1703 self.skip("Git user.name and user.email must be set")
1704
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001705 def test_devtool_upgrade(self):
1706 # Check preconditions
1707 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1708 self.track_for_cleanup(self.workspacedir)
1709 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1710 # Check parameters
1711 result = runCmd('devtool upgrade -h')
1712 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1713 self.assertIn(param, result.output)
1714 # For the moment, we are using a real recipe.
1715 recipe = 'devtool-upgrade-test1'
1716 version = '1.6.0'
1717 oldrecipefile = get_bb_var('FILE', recipe)
1718 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1719 self.track_for_cleanup(tempdir)
1720 # Check that recipe is not already under devtool control
1721 result = runCmd('devtool status')
1722 self.assertNotIn(recipe, result.output)
1723 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1724 # we are downgrading instead of upgrading.
1725 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1726 # Check if srctree at least is populated
1727 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1728 # Check new recipe subdirectory is present
1729 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1730 # Check new recipe file is present
1731 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1732 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1733 # Check devtool status and make sure recipe is present
1734 result = runCmd('devtool status')
1735 self.assertIn(recipe, result.output)
1736 self.assertIn(tempdir, result.output)
1737 # Check recipe got changed as expected
1738 with open(oldrecipefile + '.upgraded', 'r') as f:
1739 desiredlines = f.readlines()
1740 with open(newrecipefile, 'r') as f:
1741 newlines = f.readlines()
1742 self.assertEqual(desiredlines, newlines)
1743 # Check devtool reset recipe
1744 result = runCmd('devtool reset %s -n' % recipe)
1745 result = runCmd('devtool status')
1746 self.assertNotIn(recipe, result.output)
1747 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1748
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001749 def test_devtool_upgrade_git(self):
1750 # Check preconditions
1751 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1752 self.track_for_cleanup(self.workspacedir)
1753 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1754 recipe = 'devtool-upgrade-test2'
1755 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1756 oldrecipefile = get_bb_var('FILE', recipe)
1757 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1758 self.track_for_cleanup(tempdir)
1759 # Check that recipe is not already under devtool control
1760 result = runCmd('devtool status')
1761 self.assertNotIn(recipe, result.output)
1762 # Check upgrade
1763 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1764 # Check if srctree at least is populated
1765 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1766 # Check new recipe file is present
1767 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1768 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1769 # Check devtool status and make sure recipe is present
1770 result = runCmd('devtool status')
1771 self.assertIn(recipe, result.output)
1772 self.assertIn(tempdir, result.output)
1773 # Check recipe got changed as expected
1774 with open(oldrecipefile + '.upgraded', 'r') as f:
1775 desiredlines = f.readlines()
1776 with open(newrecipefile, 'r') as f:
1777 newlines = f.readlines()
1778 self.assertEqual(desiredlines, newlines)
1779 # Check devtool reset recipe
1780 result = runCmd('devtool reset %s -n' % recipe)
1781 result = runCmd('devtool status')
1782 self.assertNotIn(recipe, result.output)
1783 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1784
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001785 def test_devtool_layer_plugins(self):
1786 """Test that devtool can use plugins from other layers.
1787
1788 This test executes the selftest-reverse command from meta-selftest."""
1789
1790 self.track_for_cleanup(self.workspacedir)
1791 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1792
1793 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1794 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1795 self.assertEqual(result.output, s[::-1])
1796
1797 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1798 dstdir = basedstdir
1799 self.assertExists(dstdir)
1800 for p in paths:
1801 dstdir = os.path.join(dstdir, p)
1802 if not os.path.exists(dstdir):
1803 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001804 if p == "lib":
1805 # Can race with other tests
1806 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1807 else:
1808 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001809 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1810 if srcfile != dstfile:
1811 shutil.copy(srcfile, dstfile)
1812 self.track_for_cleanup(dstfile)
1813
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001814 def test_devtool_load_plugin(self):
1815 """Test that devtool loads only the first found plugin in BBPATH."""
1816
1817 self.track_for_cleanup(self.workspacedir)
1818 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1819
1820 devtool = runCmd("which devtool")
1821 fromname = runCmd("devtool --quiet pluginfile")
1822 srcfile = fromname.output
1823 bbpath = get_bb_var('BBPATH')
1824 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1825 plugincontent = []
1826 with open(srcfile) as fh:
1827 plugincontent = fh.readlines()
1828 try:
1829 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1830 for path in searchpath:
1831 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1832 result = runCmd("devtool --quiet count")
1833 self.assertEqual(result.output, '1')
1834 result = runCmd("devtool --quiet multiloaded")
1835 self.assertEqual(result.output, "no")
1836 for path in searchpath:
1837 result = runCmd("devtool --quiet bbdir")
1838 self.assertEqual(result.output, path)
1839 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1840 finally:
1841 with open(srcfile, 'w') as fh:
1842 fh.writelines(plugincontent)
1843
1844 def _setup_test_devtool_finish_upgrade(self):
1845 # Check preconditions
1846 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1847 self.track_for_cleanup(self.workspacedir)
1848 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1849 # Use a "real" recipe from meta-selftest
1850 recipe = 'devtool-upgrade-test1'
1851 oldversion = '1.5.3'
1852 newversion = '1.6.0'
1853 oldrecipefile = get_bb_var('FILE', recipe)
1854 recipedir = os.path.dirname(oldrecipefile)
1855 result = runCmd('git status --porcelain .', cwd=recipedir)
1856 if result.output.strip():
1857 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1858 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1859 self.track_for_cleanup(tempdir)
1860 # Check that recipe is not already under devtool control
1861 result = runCmd('devtool status')
1862 self.assertNotIn(recipe, result.output)
1863 # Do the upgrade
1864 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1865 # Check devtool status and make sure recipe is present
1866 result = runCmd('devtool status')
1867 self.assertIn(recipe, result.output)
1868 self.assertIn(tempdir, result.output)
1869 # Make a change to the source
1870 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1871 result = runCmd('git status --porcelain', cwd=tempdir)
1872 self.assertIn('M src/pv/number.c', result.output)
1873 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1874 # Check if patch is there
1875 recipedir = os.path.dirname(oldrecipefile)
1876 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1877 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001878 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001879 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001880 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1881 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001882
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001883 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001884 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001885 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1886 self.assertIn('/meta-selftest/', recipedir)
1887 # Try finish to the original layer
1888 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1889 result = runCmd('devtool finish %s meta-selftest' % recipe)
1890 result = runCmd('devtool status')
1891 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1892 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1893 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1894 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001895 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 -05001896 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1897 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1898 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1899 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 -05001900 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 -05001901 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 -05001902 with open(newrecipefile, 'r') as f:
1903 newcontent = f.read()
1904 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1905 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1906 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1907 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1908
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001909
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001910 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001911 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001912 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1913 self.assertIn('/meta-selftest/', recipedir)
1914 # Try finish to a different layer - should create a bbappend
1915 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1916 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1917 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1918 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1919 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1920 self.track_for_cleanup(newrecipedir)
1921 result = runCmd('devtool finish %s oe-core' % recipe)
1922 result = runCmd('devtool status')
1923 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1924 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1925 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1926 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001927 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001928 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1929 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1930 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 -05001931 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 -05001932 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 -05001933 with open(newrecipefile, 'r') as f:
1934 newcontent = f.read()
1935 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1936 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1937 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1938 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 -05001939
1940 def _setup_test_devtool_finish_modify(self):
1941 # Check preconditions
1942 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1943 # Try modifying a recipe
1944 self.track_for_cleanup(self.workspacedir)
1945 recipe = 'mdadm'
1946 oldrecipefile = get_bb_var('FILE', recipe)
1947 recipedir = os.path.dirname(oldrecipefile)
1948 result = runCmd('git status --porcelain .', cwd=recipedir)
1949 if result.output.strip():
1950 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1951 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1952 self.track_for_cleanup(tempdir)
1953 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1954 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1955 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1956 # Test devtool status
1957 result = runCmd('devtool status')
1958 self.assertIn(recipe, result.output)
1959 self.assertIn(tempdir, result.output)
1960 # Make a change to the source
1961 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1962 result = runCmd('git status --porcelain', cwd=tempdir)
1963 self.assertIn('M maps.c', result.output)
1964 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1965 for entry in os.listdir(recipedir):
1966 filesdir = os.path.join(recipedir, entry)
1967 if os.path.isdir(filesdir):
1968 break
1969 else:
1970 self.fail('Unable to find recipe files directory for %s' % recipe)
1971 return recipe, oldrecipefile, recipedir, filesdir
1972
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001973 def test_devtool_finish_modify_origlayer(self):
1974 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1975 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1976 self.assertIn('/meta/', recipedir)
1977 # Try finish to the original layer
1978 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1979 result = runCmd('devtool finish %s meta' % recipe)
1980 result = runCmd('devtool status')
1981 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1982 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1983 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1984 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1985 self._check_repo_status(recipedir, expected_status)
1986
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001987 def test_devtool_finish_modify_otherlayer(self):
1988 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1989 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1990 self.assertIn('/meta/', recipedir)
1991 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
1992 appenddir = os.path.join(get_test_layer(), relpth)
1993 self.track_for_cleanup(appenddir)
1994 # Try finish to the original layer
1995 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1996 result = runCmd('devtool finish %s meta-selftest' % recipe)
1997 result = runCmd('devtool status')
1998 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1999 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
2000 result = runCmd('git status --porcelain .', cwd=recipedir)
2001 if result.output.strip():
2002 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
2003 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
2004 recipefn = recipefn.split('_')[0] + '_%'
2005 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
2006 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
2007 newdir = os.path.join(appenddir, recipe)
2008 files = os.listdir(newdir)
2009 foundpatch = None
2010 for fn in files:
2011 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
2012 foundpatch = fn
2013 if not foundpatch:
2014 self.fail('No patch file created next to bbappend')
2015 files.remove(foundpatch)
2016 if files:
2017 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
2018
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002019 def test_devtool_rename(self):
2020 # Check preconditions
2021 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
2022 self.track_for_cleanup(self.workspacedir)
2023 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
2024
2025 # First run devtool add
2026 # We already have this recipe in OE-Core, but that doesn't matter
2027 recipename = 'i2c-tools'
2028 recipever = '3.1.2'
2029 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
2030 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
2031 def add_recipe():
2032 result = runCmd('devtool add %s' % url)
2033 self.assertExists(recipefile, 'Expected recipe file not created')
2034 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
2035 checkvars = {}
2036 checkvars['S'] = None
2037 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2038 self._test_recipe_contents(recipefile, checkvars, [])
2039 add_recipe()
2040 # Now rename it - change both name and version
2041 newrecipename = 'mynewrecipe'
2042 newrecipever = '456'
2043 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
2044 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
2045 self.assertExists(newrecipefile, 'Recipe file not renamed')
2046 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2047 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
2048 self.assertExists(newsrctree, 'Source directory not renamed')
2049 checkvars = {}
2050 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
2051 checkvars['SRC_URI'] = url
2052 self._test_recipe_contents(newrecipefile, checkvars, [])
2053 # Try again - change just name this time
2054 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002055 add_recipe()
2056 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
2057 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
2058 self.assertExists(newrecipefile, 'Recipe file not renamed')
2059 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
2060 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
2061 checkvars = {}
2062 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
2063 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
2064 self._test_recipe_contents(newrecipefile, checkvars, [])
2065 # Try again - change just version this time
2066 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002067 add_recipe()
2068 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
2069 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
2070 self.assertExists(newrecipefile, 'Recipe file not renamed')
2071 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
2072 checkvars = {}
2073 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
2074 checkvars['SRC_URI'] = url
2075 self._test_recipe_contents(newrecipefile, checkvars, [])
2076
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002077 def test_devtool_virtual_kernel_modify(self):
2078 """
2079 Summary: The purpose of this test case is to verify that
2080 devtool modify works correctly when building
2081 the kernel.
2082 Dependencies: NA
2083 Steps: 1. Build kernel with bitbake.
2084 2. Save the config file generated.
2085 3. Clean the environment.
2086 4. Use `devtool modify virtual/kernel` to validate following:
2087 4.1 The source is checked out correctly.
2088 4.2 The resulting configuration is the same as
2089 what was get on step 2.
2090 4.3 The Kernel can be build correctly.
2091 4.4 Changes made on the source are reflected on the
2092 subsequent builds.
2093 4.5 Changes on the configuration are reflected on the
2094 subsequent builds
2095 Expected: devtool modify is able to checkout the source of the kernel
2096 and modification to the source and configurations are reflected
2097 when building the kernel.
Patrick Williams45852732022-04-02 08:58:32 -05002098 """
2099 kernel_provider = self.td['PREFERRED_PROVIDER_virtual/kernel']
2100
Andrew Geissler82c905d2020-04-13 13:39:40 -05002101 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002102 bitbake('%s -c clean' % kernel_provider)
2103 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2104 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
2105 self.track_for_cleanup(tempdir)
2106 self.track_for_cleanup(tempdir_cfg)
2107 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002108 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04002109 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002110 #Step 1
2111 #Here is just generated the config file instead of all the kernel to optimize the
2112 #time of executing this test case.
2113 bitbake('%s -c configure' % kernel_provider)
2114 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
2115 #Step 2
2116 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
2117 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
2118
2119 tmpconfig = os.path.join(tempdir_cfg, '.config')
2120 #Step 3
2121 bitbake('%s -c clean' % kernel_provider)
2122 #Step 4.1
2123 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
2124 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2125 #Step 4.2
2126 configfile = os.path.join(tempdir,'.config')
Patrick Williams45852732022-04-02 08:58:32 -05002127 runCmd('diff %s %s' % (tmpconfig, configfile))
2128
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002129 #Step 4.3
2130 #NOTE: virtual/kernel is mapped to kernel_provider
Patrick Williams45852732022-04-02 08:58:32 -05002131 runCmd('devtool build %s' % kernel_provider)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002132 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
2133 self.assertExists(kernelfile, 'Kernel was not build correctly')
2134
2135 #Modify the kernel source
Patrick Williams45852732022-04-02 08:58:32 -05002136 modfile = os.path.join(tempdir, 'init/version.c')
Andrew Geisslerc5535c92023-01-27 16:10:19 -06002137 # Moved to uts.h in 6.1 onwards
2138 modfile2 = os.path.join(tempdir, 'include/linux/uts.h')
2139 runCmd("sed -i 's/Linux/LiNuX/g' %s %s" % (modfile, modfile2))
Patrick Williams45852732022-04-02 08:58:32 -05002140
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002141 #Modify the configuration
Patrick Williams45852732022-04-02 08:58:32 -05002142 codeconfigfile = os.path.join(tempdir, '.config.new')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002143 modconfopt = "CONFIG_SG_POOL=n"
Patrick Williams45852732022-04-02 08:58:32 -05002144 runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
2145
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002146 #Build again kernel with devtool
Patrick Williams45852732022-04-02 08:58:32 -05002147 runCmd('devtool build %s' % kernel_provider)
2148
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002149 #Step 4.4
Patrick Williams45852732022-04-02 08:58:32 -05002150 runCmd("grep '%s' %s" % ('LiNuX', kernelfile))
2151
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002152 #Step 4.5
Patrick Williams45852732022-04-02 08:58:32 -05002153 runCmd("grep %s %s" % (modconfopt, codeconfigfile))