blob: c78a68be5b4d56a915756ce2d61110bee47db5a0 [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)
279
280 @classmethod
281 def tearDownClass(cls):
282 cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
283 runCmd('rm -rf %s' % cls.devtool_sstate)
284 super(DevtoolBase, cls).tearDownClass()
285
286 def setUp(self):
287 """Test case setup function"""
288 super(DevtoolBase, self).setUp()
289 self.append_config(self.sstate_conf)
290
291
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500292class DevtoolTests(DevtoolBase):
293
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500294 def test_create_workspace(self):
295 # Check preconditions
296 result = runCmd('bitbake-layers show-layers')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400297 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 -0400298 # remove conf/devtool.conf to avoid it corrupting tests
299 devtoolconf = os.path.join(self.builddir, 'conf', 'devtool.conf')
300 self.track_for_cleanup(devtoolconf)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500301 # Try creating a workspace layer with a specific path
302 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
303 self.track_for_cleanup(tempdir)
304 result = runCmd('devtool create-workspace %s' % tempdir)
305 self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
306 result = runCmd('bitbake-layers show-layers')
307 self.assertIn(tempdir, result.output)
308 # Try creating a workspace layer with the default path
309 self.track_for_cleanup(self.workspacedir)
310 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
311 result = runCmd('devtool create-workspace')
312 self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
313 result = runCmd('bitbake-layers show-layers')
314 self.assertNotIn(tempdir, result.output)
315 self.assertIn(self.workspacedir, result.output)
316
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800317class DevtoolAddTests(DevtoolBase):
318
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500319 def test_devtool_add(self):
320 # Fetch source
321 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
322 self.track_for_cleanup(tempdir)
323 pn = 'pv'
324 pv = '1.5.3'
Andrew Geissler09209ee2020-12-13 08:44:15 -0600325 url = 'http://downloads.yoctoproject.org/mirror/sources/pv-1.5.3.tar.bz2'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500326 result = runCmd('wget %s' % url, cwd=tempdir)
327 result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
328 srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
329 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
330 # Test devtool add
331 self.track_for_cleanup(self.workspacedir)
332 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
333 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
334 result = runCmd('devtool add %s %s' % (pn, srcdir))
335 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
336 # Test devtool status
337 result = runCmd('devtool status')
338 recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
339 self.assertIn(recipepath, result.output)
340 self.assertIn(srcdir, result.output)
341 # Test devtool find-recipe
342 result = runCmd('devtool -q find-recipe %s' % pn)
343 self.assertEqual(recipepath, result.output.strip())
344 # Test devtool edit-recipe
345 result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
346 self.assertEqual('123 %s' % recipepath, result.output.strip())
347 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
348 bitbake('%s -c cleansstate' % pn)
349 # Test devtool build
350 result = runCmd('devtool build %s' % pn)
351 bb_vars = get_bb_vars(['D', 'bindir'], pn)
352 installdir = bb_vars['D']
353 self.assertTrue(installdir, 'Could not query installdir variable')
354 bindir = bb_vars['bindir']
355 self.assertTrue(bindir, 'Could not query bindir variable')
356 if bindir[0] == '/':
357 bindir = bindir[1:]
358 self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
359
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500360 def test_devtool_add_git_local(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800361 # We need dbus built so that DEPENDS recognition works
362 bitbake('dbus')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500363 # Fetch source from a remote URL, but do it outside of devtool
364 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
365 self.track_for_cleanup(tempdir)
366 pn = 'dbus-wait'
367 srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
368 # We choose an https:// git URL here to check rewriting the URL works
369 url = 'https://git.yoctoproject.org/git/dbus-wait'
370 # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
371 # instead of the directory name
372 result = runCmd('git clone %s noname' % url, cwd=tempdir)
373 srcdir = os.path.join(tempdir, 'noname')
374 result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
375 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
376 # Test devtool add
377 self.track_for_cleanup(self.workspacedir)
378 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
379 # Don't specify a name since we should be able to auto-detect it
380 result = runCmd('devtool add %s' % srcdir)
381 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
382 # Check the recipe name is correct
383 recipefile = get_bb_var('FILE', pn)
384 self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
385 self.assertIn(recipefile, result.output)
386 # Test devtool status
387 result = runCmd('devtool status')
388 self.assertIn(pn, result.output)
389 self.assertIn(srcdir, result.output)
390 self.assertIn(recipefile, result.output)
391 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000392 checkvars['LICENSE'] = 'GPL-2.0-only'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500393 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
394 checkvars['S'] = '${WORKDIR}/git'
395 checkvars['PV'] = '0.1+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000396 checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https;branch=master'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500397 checkvars['SRCREV'] = srcrev
398 checkvars['DEPENDS'] = set(['dbus'])
399 self._test_recipe_contents(recipefile, checkvars, [])
400
Patrick Williams92b42cb2022-09-03 06:53:57 -0500401 def test_devtool_add_git_style1(self):
402 version = 'v3.1.0'
403 pn = 'mbedtls'
404 # this will trigger reformat_git_uri with branch parameter in url
405 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https'"
406 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;branch=mbedtls-2.28;protocol=https"
407 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
408
409 def test_devtool_add_git_style2(self):
410 version = 'v3.1.0'
411 pn = 'mbedtls'
412 # this will trigger reformat_git_uri with branch parameter in url
413 git_url = "'git://git@github.com/ARMmbed/mbedtls.git;protocol=https'"
414 resulting_src_uri = "git://git@github.com/ARMmbed/mbedtls.git;protocol=https;branch=master"
415 self._test_devtool_add_git_url(git_url, version, pn, resulting_src_uri)
416
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500417 def test_devtool_add_library(self):
418 # Fetch source
419 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
420 self.track_for_cleanup(tempdir)
421 version = '1.1'
422 url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
423 result = runCmd('wget %s' % url, cwd=tempdir)
424 result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
425 srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
426 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
427 # Test devtool add (and use -V so we test that too)
428 self.track_for_cleanup(self.workspacedir)
429 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
430 result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
431 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
432 # Test devtool status
433 result = runCmd('devtool status')
434 self.assertIn('libftdi', result.output)
435 self.assertIn(srcdir, result.output)
436 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
437 bitbake('libftdi -c cleansstate')
438 # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
439 # There's also the matter of it installing cmake files to a path we don't
440 # normally cover, which triggers the installed-vs-shipped QA test we have
441 # within do_package
442 recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
443 result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
444 with open(recipefile, 'a') as f:
Patrick Williams213cb262021-08-07 19:21:33 -0500445 f.write('\nFILES:${PN}-dev += "${datadir}/cmake/Modules"\n')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500446 # We don't have the ability to pick up this dependency automatically yet...
447 f.write('\nDEPENDS += "libusb1"\n')
448 f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
449 # Test devtool build
450 result = runCmd('devtool build libftdi')
451 bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
452 staging_libdir = bb_vars['TESTLIBOUTPUT']
453 self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
454 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)
455 # Test devtool reset
456 stampprefix = bb_vars['STAMP']
457 result = runCmd('devtool reset libftdi')
458 result = runCmd('devtool status')
459 self.assertNotIn('libftdi', result.output)
460 self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
461 matches = glob.glob(stampprefix + '*')
462 self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
463 self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
464
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500465 def test_devtool_add_fetch(self):
466 # Fetch source
467 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
468 self.track_for_cleanup(tempdir)
469 testver = '0.23'
Brad Bishop15ae2502019-06-18 21:44:24 -0400470 url = 'https://files.pythonhosted.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-%s.tar.gz' % testver
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500471 testrecipe = 'python-markupsafe'
472 srcdir = os.path.join(tempdir, testrecipe)
473 # Test devtool add
474 self.track_for_cleanup(self.workspacedir)
475 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
476 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
477 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
478 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
479 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
480 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
481 # Test devtool status
482 result = runCmd('devtool status')
483 self.assertIn(testrecipe, result.output)
484 self.assertIn(srcdir, result.output)
485 # Check recipe
486 recipefile = get_bb_var('FILE', testrecipe)
487 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
488 checkvars = {}
489 checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
490 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
491 self._test_recipe_contents(recipefile, checkvars, [])
492 # Try with version specified
493 result = runCmd('devtool reset -n %s' % testrecipe)
494 shutil.rmtree(srcdir)
495 fakever = '1.9'
496 result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
497 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
498 # Test devtool status
499 result = runCmd('devtool status')
500 self.assertIn(testrecipe, result.output)
501 self.assertIn(srcdir, result.output)
502 # Check recipe
503 recipefile = get_bb_var('FILE', testrecipe)
504 self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
505 checkvars = {}
506 checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
507 checkvars['SRC_URI'] = url
508 self._test_recipe_contents(recipefile, checkvars, [])
Andrew Geissler615f2f12022-07-15 14:00:58 -0500509
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500510 def test_devtool_add_fetch_git(self):
511 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
512 self.track_for_cleanup(tempdir)
513 url = 'gitsm://git.yoctoproject.org/mraa'
Andrew Geissler595f6302022-01-24 19:11:47 +0000514 url_branch = '%s;branch=master' % url
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500515 checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
516 testrecipe = 'mraa'
517 srcdir = os.path.join(tempdir, testrecipe)
518 # Test devtool add
519 self.track_for_cleanup(self.workspacedir)
520 self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
521 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
522 result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
523 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
524 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
525 # Test devtool status
526 result = runCmd('devtool status')
527 self.assertIn(testrecipe, result.output)
528 self.assertIn(srcdir, result.output)
529 # Check recipe
530 recipefile = get_bb_var('FILE', testrecipe)
531 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
532 checkvars = {}
533 checkvars['S'] = '${WORKDIR}/git'
534 checkvars['PV'] = '1.0+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000535 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500536 checkvars['SRCREV'] = '${AUTOREV}'
537 self._test_recipe_contents(recipefile, checkvars, [])
538 # Try with revision and version specified
539 result = runCmd('devtool reset -n %s' % testrecipe)
540 shutil.rmtree(srcdir)
541 url_rev = '%s;rev=%s' % (url, checkrev)
542 result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
543 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
544 # Test devtool status
545 result = runCmd('devtool status')
546 self.assertIn(testrecipe, result.output)
547 self.assertIn(srcdir, result.output)
548 # Check recipe
549 recipefile = get_bb_var('FILE', testrecipe)
550 self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
551 checkvars = {}
552 checkvars['S'] = '${WORKDIR}/git'
553 checkvars['PV'] = '1.5+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000554 checkvars['SRC_URI'] = url_branch
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500555 checkvars['SRCREV'] = checkrev
556 self._test_recipe_contents(recipefile, checkvars, [])
557
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500558 def test_devtool_add_fetch_simple(self):
559 # Fetch source from a remote URL, auto-detecting name
560 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
561 self.track_for_cleanup(tempdir)
562 testver = '1.6.0'
563 url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
564 testrecipe = 'pv'
565 srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
566 # Test devtool add
567 self.track_for_cleanup(self.workspacedir)
568 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
569 result = runCmd('devtool add %s' % url)
570 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
571 self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
572 self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
573 # Test devtool status
574 result = runCmd('devtool status')
575 self.assertIn(testrecipe, result.output)
576 self.assertIn(srcdir, result.output)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500577 # Check recipedevtool add
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500578 recipefile = get_bb_var('FILE', testrecipe)
579 self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
580 checkvars = {}
581 checkvars['S'] = None
582 checkvars['SRC_URI'] = url.replace(testver, '${PV}')
583 self._test_recipe_contents(recipefile, checkvars, [])
584
Andrew Geissler82c905d2020-04-13 13:39:40 -0500585 def test_devtool_add_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600586 collections = get_bb_var('BBFILE_COLLECTIONS').split()
587 if "openembedded-layer" not in collections:
588 self.skipTest("Test needs meta-oe for nodejs")
589
Andrew Geissler82c905d2020-04-13 13:39:40 -0500590 pn = 'savoirfairelinux-node-server-example'
591 pv = '1.0.0'
592 url = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=' + pv
593 # Test devtool add
594 self.track_for_cleanup(self.workspacedir)
595 self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
596 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
597 result = runCmd('devtool add \'%s\'' % url)
598 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
599 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, '%s_%s.bb' % (pn, pv)), 'Recipe not created')
600 self.assertExists(os.path.join(self.workspacedir, 'recipes', pn, pn, 'npm-shrinkwrap.json'), 'Shrinkwrap not created')
601 # Test devtool status
602 result = runCmd('devtool status')
603 self.assertIn(pn, result.output)
604 # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
605 bitbake('%s -c cleansstate' % pn)
606 # Test devtool build
607 result = runCmd('devtool build %s' % pn)
608
Andrew Geissler615f2f12022-07-15 14:00:58 -0500609 def test_devtool_add_python_egg_requires(self):
610 # Fetch source
611 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
612 self.track_for_cleanup(tempdir)
613 testver = '0.14.0'
614 url = 'https://files.pythonhosted.org/packages/e9/9e/25d59f5043cf763833b2581c8027fa92342c4cf8ee523b498ecdf460c16d/uvicorn-%s.tar.gz' % testver
615 testrecipe = 'python3-uvicorn'
616 srcdir = os.path.join(tempdir, testrecipe)
617 # Test devtool add
618 self.track_for_cleanup(self.workspacedir)
619 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
620 result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
621
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800622class DevtoolModifyTests(DevtoolBase):
623
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500624 def test_devtool_modify(self):
625 import oe.path
626
627 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
628 self.track_for_cleanup(tempdir)
629 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500630 self.add_command_to_tearDown('bitbake -c clean mdadm')
Brad Bishop00e122a2019-10-05 11:10:57 -0400631 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500632 result = runCmd('devtool modify mdadm -x %s' % tempdir)
633 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
634 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
635 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
636 self.assertTrue(matches, 'bbappend not created %s' % result.output)
637
638 # Test devtool status
639 result = runCmd('devtool status')
640 self.assertIn('mdadm', result.output)
641 self.assertIn(tempdir, result.output)
642 self._check_src_repo(tempdir)
643
644 bitbake('mdadm -C unpack')
645
646 def check_line(checkfile, expected, message, present=True):
647 # Check for $expected, on a line on its own, in checkfile.
648 with open(checkfile, 'r') as f:
649 if present:
650 self.assertIn(expected + '\n', f, message)
651 else:
652 self.assertNotIn(expected + '\n', f, message)
653
654 modfile = os.path.join(tempdir, 'mdadm.8.in')
655 bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
656 pkgd = bb_vars['PKGD']
657 self.assertTrue(pkgd, 'Could not query PKGD variable')
658 mandir = bb_vars['mandir']
659 self.assertTrue(mandir, 'Could not query mandir variable')
660 manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
661
662 check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
663 check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
664
665 result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
666 check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
667
668 bitbake('mdadm -c package')
669 check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
670
671 result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
672 check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
673
674 bitbake('mdadm -c package')
675 check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
676
677 result = runCmd('devtool reset mdadm')
678 result = runCmd('devtool status')
679 self.assertNotIn('mdadm', result.output)
680
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500681 def test_devtool_buildclean(self):
682 def assertFile(path, *paths):
683 f = os.path.join(path, *paths)
684 self.assertExists(f)
685 def assertNoFile(path, *paths):
686 f = os.path.join(path, *paths)
687 self.assertNotExists(f)
688
689 # Clean up anything in the workdir/sysroot/sstate cache
690 bitbake('mdadm m4 -c cleansstate')
691 # Try modifying a recipe
692 tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
693 tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
694 builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
695 self.track_for_cleanup(tempdir_mdadm)
696 self.track_for_cleanup(tempdir_m4)
697 self.track_for_cleanup(builddir_m4)
698 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500699 self.add_command_to_tearDown('bitbake -c clean mdadm m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400700 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500701 self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
702 try:
703 runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
704 runCmd('devtool modify m4 -x %s' % tempdir_m4)
705 assertNoFile(tempdir_mdadm, 'mdadm')
706 assertNoFile(builddir_m4, 'src/m4')
707 result = bitbake('m4 -e')
708 result = bitbake('mdadm m4 -c compile')
709 self.assertEqual(result.status, 0)
710 assertFile(tempdir_mdadm, 'mdadm')
711 assertFile(builddir_m4, 'src/m4')
712 # Check that buildclean task exists and does call make clean
713 bitbake('mdadm m4 -c buildclean')
714 assertNoFile(tempdir_mdadm, 'mdadm')
715 assertNoFile(builddir_m4, 'src/m4')
Brad Bishop00e122a2019-10-05 11:10:57 -0400716 runCmd('echo "#Trigger rebuild" >> %s/Makefile' % tempdir_mdadm)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500717 bitbake('mdadm m4 -c compile')
718 assertFile(tempdir_mdadm, 'mdadm')
719 assertFile(builddir_m4, 'src/m4')
720 bitbake('mdadm m4 -c clean')
721 # Check that buildclean task is run before clean for B == S
722 assertNoFile(tempdir_mdadm, 'mdadm')
723 # Check that buildclean task is not run before clean for B != S
724 assertFile(builddir_m4, 'src/m4')
725 finally:
726 self.delete_recipeinc('m4')
727
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500728 def test_devtool_modify_invalid(self):
729 # Try modifying some recipes
730 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
731 self.track_for_cleanup(tempdir)
732 self.track_for_cleanup(self.workspacedir)
733 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
734
Andrew Geissler5199d832021-09-24 16:47:35 -0500735 testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500736 # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
737 result = runCmd('bitbake-layers show-recipes gcc-source*')
738 for line in result.output.splitlines():
739 # just match those lines that contain a real target
740 m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
741 if m:
742 testrecipes.append(m.group('recipe'))
743 for testrecipe in testrecipes:
744 # Check it's a valid recipe
745 bitbake('%s -e' % testrecipe)
746 # devtool extract should fail
747 result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
748 self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
749 self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
750 self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
751 # devtool modify should fail
752 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
753 self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
754 self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
755
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500756 def test_devtool_modify_native(self):
757 # Check preconditions
758 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
759 # Try modifying some recipes
760 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
761 self.track_for_cleanup(tempdir)
762 self.track_for_cleanup(self.workspacedir)
763 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
764
765 bbclassextended = False
766 inheritnative = False
Andrew Geissler4ed12e12020-06-05 18:00:41 -0500767 testrecipes = 'cdrtools-native mtools-native apt-native desktop-file-utils-native'.split()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500768 for testrecipe in testrecipes:
769 checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
770 if not bbclassextended:
771 bbclassextended = checkextend
772 if not inheritnative:
773 inheritnative = not checkextend
774 result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
775 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
776 result = runCmd('devtool build %s' % testrecipe)
777 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
778 result = runCmd('devtool reset %s' % testrecipe)
779 self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
780
781 self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
782 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 -0500783
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600784 def test_devtool_modify_localfiles_only(self):
785 # Check preconditions
786 testrecipe = 'base-files'
787 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
788 foundlocalonly = False
789 correct_symlink = False
790 for item in src_uri:
791 if item.startswith('file://'):
792 if '.patch' not in item:
793 foundlocalonly = True
794 else:
795 foundlocalonly = False
796 break
797 self.assertTrue(foundlocalonly, 'This test expects the %s recipe to fetch local files only and it seems that it no longer does' % testrecipe)
798 # Clean up anything in the workdir/sysroot/sstate cache
799 bitbake('%s -c cleansstate' % testrecipe)
800 # Try modifying a recipe
801 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
802 self.track_for_cleanup(tempdir)
803 self.track_for_cleanup(self.workspacedir)
804 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
805 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
806 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
807 srcfile = os.path.join(tempdir, 'oe-local-files/share/dot.bashrc')
808 srclink = os.path.join(tempdir, 'share/dot.bashrc')
809 self.assertExists(srcfile, 'Extracted source could not be found')
810 if os.path.islink(srclink) and os.path.exists(srclink) and os.path.samefile(srcfile, srclink):
811 correct_symlink = True
812 self.assertTrue(correct_symlink, 'Source symlink to oe-local-files is broken')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500813
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600814 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
815 self.assertTrue(matches, 'bbappend not created')
816 # Test devtool status
817 result = runCmd('devtool status')
818 self.assertIn(testrecipe, result.output)
819 self.assertIn(tempdir, result.output)
820 # Try building
821 bitbake(testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500822
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500823 def test_devtool_modify_git(self):
824 # Check preconditions
Brad Bishop316dfdd2018-06-25 12:45:53 -0400825 testrecipe = 'psplash'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500826 src_uri = get_bb_var('SRC_URI', testrecipe)
827 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
828 # Clean up anything in the workdir/sysroot/sstate cache
829 bitbake('%s -c cleansstate' % testrecipe)
830 # Try modifying a recipe
831 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
832 self.track_for_cleanup(tempdir)
833 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500834 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400835 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500836 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400837 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500838 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 -0400839 matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500840 self.assertTrue(matches, 'bbappend not created')
841 # Test devtool status
842 result = runCmd('devtool status')
843 self.assertIn(testrecipe, result.output)
844 self.assertIn(tempdir, result.output)
845 # Check git repo
846 self._check_src_repo(tempdir)
847 # Try building
848 bitbake(testrecipe)
849
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500850 def test_devtool_modify_localfiles(self):
851 # Check preconditions
852 testrecipe = 'lighttpd'
853 src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
854 foundlocal = False
855 for item in src_uri:
856 if item.startswith('file://') and '.patch' not in item:
857 foundlocal = True
858 break
859 self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
860 # Clean up anything in the workdir/sysroot/sstate cache
861 bitbake('%s -c cleansstate' % testrecipe)
862 # Try modifying a recipe
863 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
864 self.track_for_cleanup(tempdir)
865 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500866 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -0400867 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500868 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
869 self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
870 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
871 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
872 self.assertTrue(matches, 'bbappend not created')
873 # Test devtool status
874 result = runCmd('devtool status')
875 self.assertIn(testrecipe, result.output)
876 self.assertIn(tempdir, result.output)
877 # Try building
878 bitbake(testrecipe)
879
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500880 def test_devtool_modify_virtual(self):
881 # Try modifying a virtual recipe
882 virtrecipe = 'virtual/make'
883 realrecipe = 'make'
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-layers remove-layer */workspace')
888 result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
889 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
890 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
891 matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
892 self.assertTrue(matches, 'bbappend not created %s' % result.output)
893 # Test devtool status
894 result = runCmd('devtool status')
895 self.assertNotIn(virtrecipe, result.output)
896 self.assertIn(realrecipe, result.output)
897 # Check git repo
898 self._check_src_repo(tempdir)
899 # This is probably sufficient
900
Andrew Geisslerf0343792020-11-18 10:42:21 -0600901 def test_devtool_modify_overrides(self):
902 # Try modifying a recipe with patches in overrides
903 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
904 self.track_for_cleanup(tempdir)
905 self.track_for_cleanup(self.workspacedir)
906 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
907 result = runCmd('devtool modify devtool-patch-overrides -x %s' % (tempdir))
908
909 self._check_src_repo(tempdir)
910 source = os.path.join(tempdir, "source")
911 def check(branch, expected):
912 runCmd('git -C %s checkout %s' % (tempdir, branch))
913 with open(source, "rt") as f:
914 content = f.read()
915 self.assertEquals(content, expected)
916 check('devtool', 'This is a test for something\n')
917 check('devtool-no-overrides', 'This is a test for something\n')
918 check('devtool-override-qemuarm', 'This is a test for qemuarm\n')
919 check('devtool-override-qemux86', 'This is a test for qemux86\n')
920
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800921class DevtoolUpdateTests(DevtoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500922
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500923 def test_devtool_update_recipe(self):
924 # Check preconditions
925 testrecipe = 'minicom'
926 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
927 recipefile = bb_vars['FILE']
928 src_uri = bb_vars['SRC_URI']
929 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
930 self._check_repo_status(os.path.dirname(recipefile), [])
931 # First, modify a recipe
932 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
933 self.track_for_cleanup(tempdir)
934 self.track_for_cleanup(self.workspacedir)
935 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
936 # (don't bother with cleaning the recipe on teardown, we won't be building it)
937 # We don't use -x here so that we test the behaviour of devtool modify without it
938 result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
939 # Check git repo
940 self._check_src_repo(tempdir)
941 # Add a couple of commits
942 # FIXME: this only tests adding, need to also test update and remove
943 result = runCmd('echo "Additional line" >> README', cwd=tempdir)
944 result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
945 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
946 result = runCmd('git add devtool-new-file', cwd=tempdir)
947 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
948 self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
949 result = runCmd('devtool update-recipe %s' % testrecipe)
950 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
951 ('??', '.*/0001-Change-the-README.patch$'),
952 ('??', '.*/0002-Add-a-new-file.patch$')]
953 self._check_repo_status(os.path.dirname(recipefile), expected_status)
954
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500955 def test_devtool_update_recipe_git(self):
956 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -0600957 testrecipe = 'mtd-utils-selftest'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500958 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
959 recipefile = bb_vars['FILE']
960 src_uri = bb_vars['SRC_URI']
961 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
962 patches = []
963 for entry in src_uri.split():
964 if entry.startswith('file://') and entry.endswith('.patch'):
965 patches.append(entry[7:].split(';')[0])
966 self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
967 self._check_repo_status(os.path.dirname(recipefile), [])
968 # First, modify a recipe
969 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
970 self.track_for_cleanup(tempdir)
971 self.track_for_cleanup(self.workspacedir)
972 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
973 # (don't bother with cleaning the recipe on teardown, we won't be building it)
974 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
975 # Check git repo
976 self._check_src_repo(tempdir)
977 # Add a couple of commits
978 # FIXME: this only tests adding, need to also test update and remove
979 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
980 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
981 result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
982 result = runCmd('git add devtool-new-file', cwd=tempdir)
983 result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
984 self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
985 result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
986 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
987 [(' D', '.*/%s$' % patch) for patch in patches]
988 self._check_repo_status(os.path.dirname(recipefile), expected_status)
989
990 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
Andrew Geissler595f6302022-01-24 19:11:47 +0000991 addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git;branch=master"']
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500992 srcurilines = src_uri.split()
993 srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
994 srcurilines.append('"')
995 removelines = ['SRCREV = ".*"'] + srcurilines
Andrew Geissler615f2f12022-07-15 14:00:58 -0500996 self._check_diff(result.output, addlines, removelines)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500997 # Now try with auto mode
998 runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
999 result = runCmd('devtool update-recipe %s' % testrecipe)
1000 result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
1001 topleveldir = result.output.strip()
1002 relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
1003 expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
1004 ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
1005 ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
1006 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1007
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001008 def test_devtool_update_recipe_append(self):
1009 # Check preconditions
1010 testrecipe = 'mdadm'
1011 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1012 recipefile = bb_vars['FILE']
1013 src_uri = bb_vars['SRC_URI']
1014 self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
1015 self._check_repo_status(os.path.dirname(recipefile), [])
1016 # First, modify a recipe
1017 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1018 tempsrcdir = os.path.join(tempdir, 'source')
1019 templayerdir = os.path.join(tempdir, 'layer')
1020 self.track_for_cleanup(tempdir)
1021 self.track_for_cleanup(self.workspacedir)
1022 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1023 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1024 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1025 # Check git repo
1026 self._check_src_repo(tempsrcdir)
1027 # Add a commit
1028 result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
1029 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1030 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1031 # Create a temporary layer and add it to bblayers.conf
1032 self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
1033 # Create the bbappend
1034 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1035 self.assertNotIn('WARNING:', result.output)
1036 # Check recipe is still clean
1037 self._check_repo_status(os.path.dirname(recipefile), [])
1038 # Check bbappend was created
1039 splitpath = os.path.dirname(recipefile).split(os.sep)
1040 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1041 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1042 patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
1043 self.assertExists(patchfile, 'Patch file not created')
1044
1045 # Check bbappend contents
Patrick Williams213cb262021-08-07 19:21:33 -05001046 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001047 '\n',
1048 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
1049 '\n']
1050 with open(bbappendfile, 'r') as f:
1051 self.assertEqual(expectedlines, f.readlines())
1052
1053 # Check we can run it again and bbappend isn't modified
1054 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1055 with open(bbappendfile, 'r') as f:
1056 self.assertEqual(expectedlines, f.readlines())
1057 # Drop new commit and check patch gets deleted
1058 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1059 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1060 self.assertNotExists(patchfile, 'Patch file not deleted')
Patrick Williams213cb262021-08-07 19:21:33 -05001061 expectedlines2 = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001062 '\n']
1063 with open(bbappendfile, 'r') as f:
1064 self.assertEqual(expectedlines2, f.readlines())
1065 # Put commit back and check we can run it if layer isn't in bblayers.conf
1066 os.remove(bbappendfile)
1067 result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
1068 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1069 result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
1070 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1071 self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
1072 with open(bbappendfile, 'r') as f:
1073 self.assertEqual(expectedlines, f.readlines())
1074 # Deleting isn't expected to work under these circumstances
1075
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001076 def test_devtool_update_recipe_append_git(self):
1077 # Check preconditions
Patrick Williams7784c422022-11-17 07:29:11 -06001078 testrecipe = 'mtd-utils-selftest'
Andrew Geissler517393d2023-01-13 08:55:19 -06001079 bb_vars = get_bb_vars(['FILE', 'SRC_URI', 'LAYERSERIES_CORENAMES'], testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001080 recipefile = bb_vars['FILE']
1081 src_uri = bb_vars['SRC_URI']
Andrew Geissler517393d2023-01-13 08:55:19 -06001082 corenames = bb_vars['LAYERSERIES_CORENAMES']
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001083 self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
1084 for entry in src_uri.split():
1085 if entry.startswith('git://'):
1086 git_uri = entry
1087 break
1088 self._check_repo_status(os.path.dirname(recipefile), [])
1089 # First, modify a recipe
1090 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1091 tempsrcdir = os.path.join(tempdir, 'source')
1092 templayerdir = os.path.join(tempdir, 'layer')
1093 self.track_for_cleanup(tempdir)
1094 self.track_for_cleanup(self.workspacedir)
1095 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1096 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1097 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
1098 # Check git repo
1099 self._check_src_repo(tempsrcdir)
1100 # Add a commit
1101 result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
1102 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1103 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
1104 # Create a temporary layer
1105 os.makedirs(os.path.join(templayerdir, 'conf'))
1106 with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
1107 f.write('BBPATH .= ":${LAYERDIR}"\n')
1108 f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
1109 f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
1110 f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
1111 f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
1112 f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
Andrew Geissler517393d2023-01-13 08:55:19 -06001113 f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "%s"\n' % corenames)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001114 self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
1115 result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
1116 # Create the bbappend
1117 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1118 self.assertNotIn('WARNING:', result.output)
1119 # Check recipe is still clean
1120 self._check_repo_status(os.path.dirname(recipefile), [])
1121 # Check bbappend was created
1122 splitpath = os.path.dirname(recipefile).split(os.sep)
1123 appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
1124 bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
1125 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1126
1127 # Check bbappend contents
1128 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1129 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1130 '\n',
1131 'SRC_URI = "%s"\n' % git_uri,
1132 '\n'])
1133 with open(bbappendfile, 'r') as f:
1134 self.assertEqual(expectedlines, set(f.readlines()))
1135
1136 # Check we can run it again and bbappend isn't modified
1137 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1138 with open(bbappendfile, 'r') as f:
1139 self.assertEqual(expectedlines, set(f.readlines()))
1140 # Drop new commit and check SRCREV changes
1141 result = runCmd('git reset HEAD^', cwd=tempsrcdir)
1142 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1143 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1144 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1145 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1146 '\n',
1147 'SRC_URI = "%s"\n' % git_uri,
1148 '\n'])
1149 with open(bbappendfile, 'r') as f:
1150 self.assertEqual(expectedlines, set(f.readlines()))
1151 # Put commit back and check we can run it if layer isn't in bblayers.conf
1152 os.remove(bbappendfile)
1153 result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
1154 result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
1155 result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
1156 self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
1157 self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
1158 result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
1159 expectedlines = set(['SRCREV = "%s"\n' % result.output,
1160 '\n',
1161 'SRC_URI = "%s"\n' % git_uri,
1162 '\n'])
1163 with open(bbappendfile, 'r') as f:
1164 self.assertEqual(expectedlines, set(f.readlines()))
1165 # Deleting isn't expected to work under these circumstances
1166
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001167 def test_devtool_update_recipe_local_files(self):
1168 """Check that local source files are copied over instead of patched"""
1169 testrecipe = 'makedevs'
1170 recipefile = get_bb_var('FILE', testrecipe)
1171 # Setup srctree for modifying the recipe
1172 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1173 self.track_for_cleanup(tempdir)
1174 self.track_for_cleanup(self.workspacedir)
1175 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1176 # (don't bother with cleaning the recipe on teardown, we won't be
1177 # building it)
1178 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1179 # Check git repo
1180 self._check_src_repo(tempdir)
1181 # Try building just to ensure we haven't broken that
1182 bitbake("%s" % testrecipe)
1183 # Edit / commit local source
1184 runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
1185 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1186 runCmd('echo "Bar" > new-file', cwd=tempdir)
1187 runCmd('git add new-file', cwd=tempdir)
1188 runCmd('git commit -m "Add new file"', cwd=tempdir)
1189 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1190 os.path.dirname(recipefile))
1191 runCmd('devtool update-recipe %s' % testrecipe)
1192 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1193 (' M', '.*/makedevs/makedevs.c$'),
1194 ('??', '.*/makedevs/new-local$'),
1195 ('??', '.*/makedevs/0001-Add-new-file.patch$')]
1196 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1197
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001198 def test_devtool_update_recipe_local_files_2(self):
1199 """Check local source files support when oe-local-files is in Git"""
Brad Bishop316dfdd2018-06-25 12:45:53 -04001200 testrecipe = 'devtool-test-local'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001201 recipefile = get_bb_var('FILE', testrecipe)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001202 recipedir = os.path.dirname(recipefile)
1203 result = runCmd('git status --porcelain .', cwd=recipedir)
1204 if result.output.strip():
1205 self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001206 # Setup srctree for modifying the recipe
1207 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1208 self.track_for_cleanup(tempdir)
1209 self.track_for_cleanup(self.workspacedir)
1210 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1211 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1212 # Check git repo
1213 self._check_src_repo(tempdir)
1214 # Add oe-local-files to Git
1215 runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
1216 runCmd('git add oe-local-files', cwd=tempdir)
1217 runCmd('git commit -m "Add local sources"', cwd=tempdir)
1218 # Edit / commit local sources
Brad Bishop316dfdd2018-06-25 12:45:53 -04001219 runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001220 runCmd('git commit -am "Edit existing file"', cwd=tempdir)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001221 runCmd('git rm oe-local-files/file2', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001222 runCmd('git commit -m"Remove file"', cwd=tempdir)
1223 runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
1224 runCmd('git add oe-local-files/new-local', cwd=tempdir)
1225 runCmd('git commit -m "Add new local file"', cwd=tempdir)
1226 runCmd('echo "Gar" > new-file', cwd=tempdir)
1227 runCmd('git add new-file', cwd=tempdir)
1228 runCmd('git commit -m "Add new file"', cwd=tempdir)
1229 self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
1230 os.path.dirname(recipefile))
1231 # Checkout unmodified file to working copy -> devtool should still pick
1232 # the modified version from HEAD
Brad Bishop316dfdd2018-06-25 12:45:53 -04001233 runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001234 runCmd('devtool update-recipe %s' % testrecipe)
1235 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
Brad Bishop316dfdd2018-06-25 12:45:53 -04001236 (' M', '.*/file1$'),
1237 (' D', '.*/file2$'),
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001238 ('??', '.*/new-local$'),
1239 ('??', '.*/0001-Add-new-file.patch$')]
1240 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1241
Andrew Geissler4ed12e12020-06-05 18:00:41 -05001242 def test_devtool_update_recipe_with_gitignore(self):
1243 # First, modify the recipe
1244 testrecipe = 'devtool-test-ignored'
1245 bb_vars = get_bb_vars(['FILE'], testrecipe)
1246 recipefile = bb_vars['FILE']
1247 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch')
1248 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, testrecipe + '.patch.expected')
1249 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1250 self.track_for_cleanup(tempdir)
1251 self.track_for_cleanup(self.workspacedir)
1252 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1253 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1254 result = runCmd('devtool modify %s' % testrecipe)
1255 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1256 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1257 # Check recipe got changed as expected
1258 with open(newpatchfile, 'r') as f:
1259 desiredlines = f.readlines()
1260 with open(patchfile, 'r') as f:
1261 newlines = f.readlines()
1262 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1263 # which changes the metadata subject which is added into the patch, but keep
1264 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1265 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1266 self.assertEqual(desiredlines[5:], newlines[5:])
1267
1268 def test_devtool_update_recipe_long_filename(self):
1269 # First, modify the recipe
1270 testrecipe = 'devtool-test-long-filename'
1271 bb_vars = get_bb_vars(['FILE'], testrecipe)
1272 recipefile = bb_vars['FILE']
1273 patchfilename = '0001-I-ll-patch-you-only-if-devtool-lets-me-to-do-it-corr.patch'
1274 patchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename)
1275 newpatchfile = os.path.join(os.path.dirname(recipefile), testrecipe, patchfilename + '.expected')
1276 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1277 self.track_for_cleanup(tempdir)
1278 self.track_for_cleanup(self.workspacedir)
1279 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1280 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1281 result = runCmd('devtool modify %s' % testrecipe)
1282 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1283 result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
1284 # Check recipe got changed as expected
1285 with open(newpatchfile, 'r') as f:
1286 desiredlines = f.readlines()
1287 with open(patchfile, 'r') as f:
1288 newlines = f.readlines()
1289 # Ignore the initial lines, because oe-selftest creates own meta-selftest repo
1290 # which changes the metadata subject which is added into the patch, but keep
1291 # .patch.expected as it is in case someone runs devtool finish --force-patch-refresh
1292 # devtool-test-ignored manually, then it should generate exactly the same .patch file
1293 self.assertEqual(desiredlines[5:], newlines[5:])
1294
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001295 def test_devtool_update_recipe_local_files_3(self):
1296 # First, modify the recipe
1297 testrecipe = 'devtool-test-localonly'
1298 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1299 recipefile = bb_vars['FILE']
1300 src_uri = bb_vars['SRC_URI']
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 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1306 result = runCmd('devtool modify %s' % testrecipe)
1307 # Modify one file
1308 runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
1309 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1310 result = runCmd('devtool update-recipe %s' % testrecipe)
1311 expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
1312 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1313
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001314 def test_devtool_update_recipe_local_patch_gz(self):
1315 # First, modify the recipe
1316 testrecipe = 'devtool-test-patch-gz'
1317 if get_bb_var('DISTRO') == 'poky-tiny':
1318 self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
1319 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1320 recipefile = bb_vars['FILE']
1321 src_uri = bb_vars['SRC_URI']
1322 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1323 self.track_for_cleanup(tempdir)
1324 self.track_for_cleanup(self.workspacedir)
1325 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1326 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1327 result = runCmd('devtool modify %s' % testrecipe)
1328 # Modify one file
1329 srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
1330 runCmd('echo "Another line" >> README', cwd=srctree)
1331 runCmd('git commit -a --amend --no-edit', cwd=srctree)
1332 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1333 result = runCmd('devtool update-recipe %s' % testrecipe)
1334 expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
1335 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1336 patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
1337 result = runCmd('file %s' % patch_gz)
1338 if 'gzip compressed data' not in result.output:
1339 self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
1340
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001341 def test_devtool_update_recipe_local_files_subdir(self):
1342 # Try devtool update-recipe on a recipe that has a file with subdir= set in
1343 # SRC_URI such that it overwrites a file that was in an archive that
1344 # was also in SRC_URI
1345 # First, modify the recipe
1346 testrecipe = 'devtool-test-subdir'
1347 bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
1348 recipefile = bb_vars['FILE']
1349 src_uri = bb_vars['SRC_URI']
1350 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1351 self.track_for_cleanup(tempdir)
1352 self.track_for_cleanup(self.workspacedir)
1353 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1354 # (don't bother with cleaning the recipe on teardown, we won't be building it)
1355 result = runCmd('devtool modify %s' % testrecipe)
1356 testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
1357 self.assertExists(testfile, 'Extracted source could not be found')
1358 with open(testfile, 'r') as f:
1359 contents = f.read().rstrip()
1360 self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
1361 # Test devtool update-recipe without modifying any files
1362 self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
1363 result = runCmd('devtool update-recipe %s' % testrecipe)
1364 expected_status = []
1365 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1366
Andrew Geissler615f2f12022-07-15 14:00:58 -05001367 def test_devtool_finish_modify_git_subdir(self):
1368 # Check preconditions
1369 testrecipe = 'dos2unix'
1370 bb_vars = get_bb_vars(['SRC_URI', 'S', 'WORKDIR', 'FILE'], testrecipe)
1371 self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe)
1372 workdir_git = '%s/git/' % bb_vars['WORKDIR']
1373 if not bb_vars['S'].startswith(workdir_git):
1374 self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe)
1375 subdir = bb_vars['S'].split(workdir_git, 1)[1]
1376 # Clean up anything in the workdir/sysroot/sstate cache
1377 bitbake('%s -c cleansstate' % testrecipe)
1378 # Try modifying a recipe
1379 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1380 self.track_for_cleanup(tempdir)
1381 self.track_for_cleanup(self.workspacedir)
1382 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
1383 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1384 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1385 testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c')
1386 self.assertExists(testsrcfile, 'Extracted source could not be found')
1387 self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
1388 self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo')
1389 # Check git repo
1390 self._check_src_repo(tempdir)
1391 # Modify file
1392 runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile)
1393 result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir)
1394 # Now try updating original recipe
1395 recipefile = bb_vars['FILE']
1396 recipedir = os.path.dirname(recipefile)
1397 self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1398 result = runCmd('devtool update-recipe %s' % testrecipe)
1399 expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
1400 ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))]
1401 self._check_repo_status(os.path.dirname(recipefile), expected_status)
1402 result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
1403 removelines = ['SRC_URI = "git://.*"']
1404 addlines = [
1405 'SRC_URI = "git://.* \\\\',
1406 'file://0001-Add-a-comment.patch;patchdir=.. \\\\',
1407 '"'
1408 ]
1409 self._check_diff(result.output, addlines, removelines)
1410 # Put things back so we can run devtool finish on a different layer
1411 runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
1412 # Run devtool finish
1413 res = re.search('recipes-.*', recipedir)
1414 self.assertTrue(res, 'Unable to find recipe subdirectory')
1415 recipesubdir = res[0]
1416 self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir))
1417 result = runCmd('devtool finish %s meta-selftest' % testrecipe)
1418 # Check bbappend file contents
1419 appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe)
1420 with open(appendfn, 'r') as f:
1421 appendlines = f.readlines()
1422 expected_appendlines = [
1423 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
1424 '\n',
1425 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n',
1426 '\n'
1427 ]
1428 self.assertEqual(appendlines, expected_appendlines)
1429 self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch'))
1430 # Try building
1431 bitbake('%s -c patch' % testrecipe)
1432
1433
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001434class DevtoolExtractTests(DevtoolBase):
1435
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001436 def test_devtool_extract(self):
1437 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1438 # Try devtool extract
1439 self.track_for_cleanup(tempdir)
1440 self.track_for_cleanup(self.workspacedir)
1441 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1442 result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
1443 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1444 self._check_src_repo(tempdir)
1445
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001446 def test_devtool_extract_virtual(self):
1447 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1448 # Try devtool extract
1449 self.track_for_cleanup(tempdir)
1450 self.track_for_cleanup(self.workspacedir)
1451 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1452 result = runCmd('devtool extract virtual/make %s' % tempdir)
1453 self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
1454 self._check_src_repo(tempdir)
1455
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001456 def test_devtool_reset_all(self):
1457 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1458 self.track_for_cleanup(tempdir)
1459 self.track_for_cleanup(self.workspacedir)
1460 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1461 testrecipe1 = 'mdadm'
1462 testrecipe2 = 'cronie'
1463 result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
1464 result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
1465 result = runCmd('devtool build %s' % testrecipe1)
1466 result = runCmd('devtool build %s' % testrecipe2)
1467 stampprefix1 = get_bb_var('STAMP', testrecipe1)
1468 self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
1469 stampprefix2 = get_bb_var('STAMP', testrecipe2)
1470 self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
1471 result = runCmd('devtool reset -a')
1472 self.assertIn(testrecipe1, result.output)
1473 self.assertIn(testrecipe2, result.output)
1474 result = runCmd('devtool status')
1475 self.assertNotIn(testrecipe1, result.output)
1476 self.assertNotIn(testrecipe2, result.output)
1477 matches1 = glob.glob(stampprefix1 + '*')
1478 self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
1479 matches2 = glob.glob(stampprefix2 + '*')
1480 self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
1481
Patrick Williams45852732022-04-02 08:58:32 -05001482 @OETestTag("runqemu")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001483 def test_devtool_deploy_target(self):
1484 # NOTE: Whilst this test would seemingly be better placed as a runtime test,
1485 # unfortunately the runtime tests run under bitbake and you can't run
1486 # devtool within bitbake (since devtool needs to run bitbake itself).
1487 # Additionally we are testing build-time functionality as well, so
1488 # really this has to be done as an oe-selftest test.
1489 #
1490 # Check preconditions
1491 machine = get_bb_var('MACHINE')
1492 if not machine.startswith('qemu'):
1493 self.skipTest('This test only works with qemu machines')
1494 if not os.path.exists('/etc/runqemu-nosudo'):
1495 self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1496 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
1497 if result.status != 0:
1498 result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
1499 if result.status != 0:
1500 self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
1501 for line in result.output.splitlines():
1502 if line.startswith('tap'):
1503 break
1504 else:
1505 self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
1506 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1507 # Definitions
1508 testrecipe = 'mdadm'
1509 testfile = '/sbin/mdadm'
1510 testimage = 'oe-selftest-image'
1511 testcommand = '/sbin/mdadm --help'
1512 # Build an image to run
1513 bitbake("%s qemu-native qemu-helper-native" % testimage)
1514 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1515 self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
1516 self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
1517 # Clean recipe so the first deploy will fail
1518 bitbake("%s -c clean" % testrecipe)
1519 # Try devtool modify
1520 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1521 self.track_for_cleanup(tempdir)
1522 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001523 self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
Brad Bishop00e122a2019-10-05 11:10:57 -04001524 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001525 result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
1526 # Test that deploy-target at this point fails (properly)
1527 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
1528 self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
1529 self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
1530 result = runCmd('devtool build %s' % testrecipe)
1531 # First try a dry-run of deploy-target
1532 result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
1533 self.assertIn(' %s' % testfile, result.output)
1534 # Boot the image
1535 with runqemu(testimage) as qemu:
1536 # Now really test deploy-target
1537 result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1538 # Run a test command to see if it was installed properly
1539 sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
1540 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
1541 # Check if it deployed all of the files with the right ownership/perms
1542 # First look on the host - need to do this under pseudo to get the correct ownership/perms
1543 bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
1544 installdir = bb_vars['D']
1545 fakerootenv = bb_vars['FAKEROOTENV']
1546 fakerootcmd = bb_vars['FAKEROOTCMD']
Brad Bishop19323692019-04-05 15:28:33 -04001547 result = runCmd('%s %s find . -type f -exec ls -l {} \\;' % (fakerootenv, fakerootcmd), cwd=installdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001548 filelist1 = self._process_ls_output(result.output)
1549
1550 # Now look on the target
1551 tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
1552 self.track_for_cleanup(tempdir2)
1553 tmpfilelist = os.path.join(tempdir2, 'files.txt')
1554 with open(tmpfilelist, 'w') as f:
1555 for line in filelist1:
1556 splitline = line.split()
1557 f.write(splitline[-1] + '\n')
1558 result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
1559 filelist2 = self._process_ls_output(result.output)
1560 filelist1.sort(key=lambda item: item.split()[-1])
1561 filelist2.sort(key=lambda item: item.split()[-1])
1562 self.assertEqual(filelist1, filelist2)
1563 # Test undeploy-target
1564 result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
1565 result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
1566 self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
1567
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001568 def test_devtool_build_image(self):
1569 """Test devtool build-image plugin"""
1570 # Check preconditions
1571 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1572 image = 'core-image-minimal'
1573 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001574 self.add_command_to_tearDown('bitbake -c clean %s' % image)
Brad Bishop00e122a2019-10-05 11:10:57 -04001575 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001576 bitbake('%s -c clean' % image)
1577 # Add target and native recipes to workspace
1578 recipes = ['mdadm', 'parted-native']
1579 for recipe in recipes:
1580 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1581 self.track_for_cleanup(tempdir)
1582 self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
1583 runCmd('devtool modify %s -x %s' % (recipe, tempdir))
1584 # Try to build image
1585 result = runCmd('devtool build-image %s' % image)
1586 self.assertNotEqual(result, 0, 'devtool build-image failed')
1587 # Check if image contains expected packages
1588 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
1589 image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
1590 reqpkgs = [item for item in recipes if not item.endswith('-native')]
1591 with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
1592 for line in f:
1593 splitval = line.split()
1594 if splitval:
1595 pkg = splitval[0]
1596 if pkg in reqpkgs:
1597 reqpkgs.remove(pkg)
1598 if reqpkgs:
1599 self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
1600
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001601class DevtoolUpgradeTests(DevtoolBase):
1602
Patrick Williams45852732022-04-02 08:58:32 -05001603 def setUp(self):
1604 super().setUp()
1605 try:
1606 runCmd("git config --global user.name")
1607 runCmd("git config --global user.email")
1608 except:
1609 self.skip("Git user.name and user.email must be set")
1610
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001611 def test_devtool_upgrade(self):
1612 # Check preconditions
1613 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1614 self.track_for_cleanup(self.workspacedir)
1615 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1616 # Check parameters
1617 result = runCmd('devtool upgrade -h')
1618 for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
1619 self.assertIn(param, result.output)
1620 # For the moment, we are using a real recipe.
1621 recipe = 'devtool-upgrade-test1'
1622 version = '1.6.0'
1623 oldrecipefile = get_bb_var('FILE', recipe)
1624 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1625 self.track_for_cleanup(tempdir)
1626 # Check that recipe is not already under devtool control
1627 result = runCmd('devtool status')
1628 self.assertNotIn(recipe, result.output)
1629 # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
1630 # we are downgrading instead of upgrading.
1631 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
1632 # Check if srctree at least is populated
1633 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
1634 # Check new recipe subdirectory is present
1635 self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
1636 # Check new recipe file is present
1637 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
1638 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1639 # Check devtool status and make sure recipe is present
1640 result = runCmd('devtool status')
1641 self.assertIn(recipe, result.output)
1642 self.assertIn(tempdir, result.output)
1643 # Check recipe got changed as expected
1644 with open(oldrecipefile + '.upgraded', 'r') as f:
1645 desiredlines = f.readlines()
1646 with open(newrecipefile, 'r') as f:
1647 newlines = f.readlines()
1648 self.assertEqual(desiredlines, newlines)
1649 # Check devtool reset recipe
1650 result = runCmd('devtool reset %s -n' % recipe)
1651 result = runCmd('devtool status')
1652 self.assertNotIn(recipe, result.output)
1653 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1654
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001655 def test_devtool_upgrade_git(self):
1656 # Check preconditions
1657 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1658 self.track_for_cleanup(self.workspacedir)
1659 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1660 recipe = 'devtool-upgrade-test2'
1661 commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
1662 oldrecipefile = get_bb_var('FILE', recipe)
1663 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1664 self.track_for_cleanup(tempdir)
1665 # Check that recipe is not already under devtool control
1666 result = runCmd('devtool status')
1667 self.assertNotIn(recipe, result.output)
1668 # Check upgrade
1669 result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
1670 # Check if srctree at least is populated
1671 self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
1672 # Check new recipe file is present
1673 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
1674 self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
1675 # Check devtool status and make sure recipe is present
1676 result = runCmd('devtool status')
1677 self.assertIn(recipe, result.output)
1678 self.assertIn(tempdir, result.output)
1679 # Check recipe got changed as expected
1680 with open(oldrecipefile + '.upgraded', 'r') as f:
1681 desiredlines = f.readlines()
1682 with open(newrecipefile, 'r') as f:
1683 newlines = f.readlines()
1684 self.assertEqual(desiredlines, newlines)
1685 # Check devtool reset recipe
1686 result = runCmd('devtool reset %s -n' % recipe)
1687 result = runCmd('devtool status')
1688 self.assertNotIn(recipe, result.output)
1689 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
1690
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001691 def test_devtool_layer_plugins(self):
1692 """Test that devtool can use plugins from other layers.
1693
1694 This test executes the selftest-reverse command from meta-selftest."""
1695
1696 self.track_for_cleanup(self.workspacedir)
1697 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1698
1699 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1700 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1701 self.assertEqual(result.output, s[::-1])
1702
1703 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
1704 dstdir = basedstdir
1705 self.assertExists(dstdir)
1706 for p in paths:
1707 dstdir = os.path.join(dstdir, p)
1708 if not os.path.exists(dstdir):
1709 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -05001710 if p == "lib":
1711 # Can race with other tests
1712 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
1713 else:
1714 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001715 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
1716 if srcfile != dstfile:
1717 shutil.copy(srcfile, dstfile)
1718 self.track_for_cleanup(dstfile)
1719
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001720 def test_devtool_load_plugin(self):
1721 """Test that devtool loads only the first found plugin in BBPATH."""
1722
1723 self.track_for_cleanup(self.workspacedir)
1724 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1725
1726 devtool = runCmd("which devtool")
1727 fromname = runCmd("devtool --quiet pluginfile")
1728 srcfile = fromname.output
1729 bbpath = get_bb_var('BBPATH')
1730 searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
1731 plugincontent = []
1732 with open(srcfile) as fh:
1733 plugincontent = fh.readlines()
1734 try:
1735 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
1736 for path in searchpath:
1737 self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
1738 result = runCmd("devtool --quiet count")
1739 self.assertEqual(result.output, '1')
1740 result = runCmd("devtool --quiet multiloaded")
1741 self.assertEqual(result.output, "no")
1742 for path in searchpath:
1743 result = runCmd("devtool --quiet bbdir")
1744 self.assertEqual(result.output, path)
1745 os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
1746 finally:
1747 with open(srcfile, 'w') as fh:
1748 fh.writelines(plugincontent)
1749
1750 def _setup_test_devtool_finish_upgrade(self):
1751 # Check preconditions
1752 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1753 self.track_for_cleanup(self.workspacedir)
1754 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1755 # Use a "real" recipe from meta-selftest
1756 recipe = 'devtool-upgrade-test1'
1757 oldversion = '1.5.3'
1758 newversion = '1.6.0'
1759 oldrecipefile = get_bb_var('FILE', recipe)
1760 recipedir = os.path.dirname(oldrecipefile)
1761 result = runCmd('git status --porcelain .', cwd=recipedir)
1762 if result.output.strip():
1763 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1764 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1765 self.track_for_cleanup(tempdir)
1766 # Check that recipe is not already under devtool control
1767 result = runCmd('devtool status')
1768 self.assertNotIn(recipe, result.output)
1769 # Do the upgrade
1770 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1771 # Check devtool status and make sure recipe is present
1772 result = runCmd('devtool status')
1773 self.assertIn(recipe, result.output)
1774 self.assertIn(tempdir, result.output)
1775 # Make a change to the source
1776 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1777 result = runCmd('git status --porcelain', cwd=tempdir)
1778 self.assertIn('M src/pv/number.c', result.output)
1779 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1780 # Check if patch is there
1781 recipedir = os.path.dirname(oldrecipefile)
1782 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1783 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
Brad Bishop6dbb3162019-11-25 09:41:34 -05001784 backportedpatchfn = 'backported.patch'
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001785 self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001786 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Backported patch file does not exist')
1787 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001788
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001789 def test_devtool_finish_upgrade_origlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001790 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001791 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1792 self.assertIn('/meta-selftest/', recipedir)
1793 # Try finish to the original layer
1794 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1795 result = runCmd('devtool finish %s meta-selftest' % recipe)
1796 result = runCmd('devtool status')
1797 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1798 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1799 self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
1800 self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001801 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 -05001802 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1803 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1804 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1805 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 -05001806 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 -05001807 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 -05001808 with open(newrecipefile, 'r') as f:
1809 newcontent = f.read()
1810 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1811 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1812 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1813 self.assertIn("http://www.ivarch.com/programs/sources/pv-${PV}.tar.gz", newcontent, "New recipe no longer has upstream source in SRC_URI")
1814
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001815
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001816 def test_devtool_finish_upgrade_otherlayer(self):
Brad Bishop6dbb3162019-11-25 09:41:34 -05001817 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn, backportedpatchfn = self._setup_test_devtool_finish_upgrade()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001818 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1819 self.assertIn('/meta-selftest/', recipedir)
1820 # Try finish to a different layer - should create a bbappend
1821 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1822 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1823 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1824 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1825 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1826 self.track_for_cleanup(newrecipedir)
1827 result = runCmd('devtool finish %s oe-core' % recipe)
1828 result = runCmd('devtool status')
1829 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1830 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1831 self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
1832 self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
Brad Bishop6dbb3162019-11-25 09:41:34 -05001833 self.assertExists(os.path.join(olddir, backportedpatchfn), 'Old backported patch file should not have been deleted')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001834 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1835 self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
1836 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 -05001837 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 -05001838 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 -05001839 with open(newrecipefile, 'r') as f:
1840 newcontent = f.read()
1841 self.assertNotIn(backportedpatchfn, newcontent, "Backported patch should have been removed from the recipe but wasn't")
1842 self.assertIn(patchfn, newcontent, "Old patch should have not been removed from the recipe but was")
1843 self.assertIn("0002-Add-a-comment-to-the-code.patch", newcontent, "New patch should have been added to the recipe but wasn't")
1844 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 -05001845
1846 def _setup_test_devtool_finish_modify(self):
1847 # Check preconditions
1848 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1849 # Try modifying a recipe
1850 self.track_for_cleanup(self.workspacedir)
1851 recipe = 'mdadm'
1852 oldrecipefile = get_bb_var('FILE', recipe)
1853 recipedir = os.path.dirname(oldrecipefile)
1854 result = runCmd('git status --porcelain .', cwd=recipedir)
1855 if result.output.strip():
1856 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1857 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1858 self.track_for_cleanup(tempdir)
1859 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1860 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1861 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
1862 # Test devtool status
1863 result = runCmd('devtool status')
1864 self.assertIn(recipe, result.output)
1865 self.assertIn(tempdir, result.output)
1866 # Make a change to the source
1867 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1868 result = runCmd('git status --porcelain', cwd=tempdir)
1869 self.assertIn('M maps.c', result.output)
1870 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1871 for entry in os.listdir(recipedir):
1872 filesdir = os.path.join(recipedir, entry)
1873 if os.path.isdir(filesdir):
1874 break
1875 else:
1876 self.fail('Unable to find recipe files directory for %s' % recipe)
1877 return recipe, oldrecipefile, recipedir, filesdir
1878
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001879 def test_devtool_finish_modify_origlayer(self):
1880 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1881 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1882 self.assertIn('/meta/', recipedir)
1883 # Try finish to the original layer
1884 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1885 result = runCmd('devtool finish %s meta' % recipe)
1886 result = runCmd('devtool status')
1887 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1888 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1889 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1890 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1891 self._check_repo_status(recipedir, expected_status)
1892
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001893 def test_devtool_finish_modify_otherlayer(self):
1894 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1895 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1896 self.assertIn('/meta/', recipedir)
1897 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
1898 appenddir = os.path.join(get_test_layer(), relpth)
1899 self.track_for_cleanup(appenddir)
1900 # Try finish to the original layer
1901 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1902 result = runCmd('devtool finish %s meta-selftest' % recipe)
1903 result = runCmd('devtool status')
1904 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1905 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
1906 result = runCmd('git status --porcelain .', cwd=recipedir)
1907 if result.output.strip():
1908 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
1909 recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
1910 recipefn = recipefn.split('_')[0] + '_%'
1911 appendfile = os.path.join(appenddir, recipefn + '.bbappend')
1912 self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
1913 newdir = os.path.join(appenddir, recipe)
1914 files = os.listdir(newdir)
1915 foundpatch = None
1916 for fn in files:
1917 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
1918 foundpatch = fn
1919 if not foundpatch:
1920 self.fail('No patch file created next to bbappend')
1921 files.remove(foundpatch)
1922 if files:
1923 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
1924
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001925 def test_devtool_rename(self):
1926 # Check preconditions
1927 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1928 self.track_for_cleanup(self.workspacedir)
1929 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1930
1931 # First run devtool add
1932 # We already have this recipe in OE-Core, but that doesn't matter
1933 recipename = 'i2c-tools'
1934 recipever = '3.1.2'
1935 recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
1936 url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
1937 def add_recipe():
1938 result = runCmd('devtool add %s' % url)
1939 self.assertExists(recipefile, 'Expected recipe file not created')
1940 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
1941 checkvars = {}
1942 checkvars['S'] = None
1943 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1944 self._test_recipe_contents(recipefile, checkvars, [])
1945 add_recipe()
1946 # Now rename it - change both name and version
1947 newrecipename = 'mynewrecipe'
1948 newrecipever = '456'
1949 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
1950 result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
1951 self.assertExists(newrecipefile, 'Recipe file not renamed')
1952 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1953 newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
1954 self.assertExists(newsrctree, 'Source directory not renamed')
1955 checkvars = {}
1956 checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
1957 checkvars['SRC_URI'] = url
1958 self._test_recipe_contents(newrecipefile, checkvars, [])
1959 # Try again - change just name this time
1960 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001961 add_recipe()
1962 newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
1963 result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
1964 self.assertExists(newrecipefile, 'Recipe file not renamed')
1965 self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
1966 self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
1967 checkvars = {}
1968 checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
1969 checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
1970 self._test_recipe_contents(newrecipefile, checkvars, [])
1971 # Try again - change just version this time
1972 result = runCmd('devtool reset -n %s' % newrecipename)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001973 add_recipe()
1974 newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
1975 result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
1976 self.assertExists(newrecipefile, 'Recipe file not renamed')
1977 self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
1978 checkvars = {}
1979 checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
1980 checkvars['SRC_URI'] = url
1981 self._test_recipe_contents(newrecipefile, checkvars, [])
1982
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001983 def test_devtool_virtual_kernel_modify(self):
1984 """
1985 Summary: The purpose of this test case is to verify that
1986 devtool modify works correctly when building
1987 the kernel.
1988 Dependencies: NA
1989 Steps: 1. Build kernel with bitbake.
1990 2. Save the config file generated.
1991 3. Clean the environment.
1992 4. Use `devtool modify virtual/kernel` to validate following:
1993 4.1 The source is checked out correctly.
1994 4.2 The resulting configuration is the same as
1995 what was get on step 2.
1996 4.3 The Kernel can be build correctly.
1997 4.4 Changes made on the source are reflected on the
1998 subsequent builds.
1999 4.5 Changes on the configuration are reflected on the
2000 subsequent builds
2001 Expected: devtool modify is able to checkout the source of the kernel
2002 and modification to the source and configurations are reflected
2003 when building the kernel.
Patrick Williams45852732022-04-02 08:58:32 -05002004 """
2005 kernel_provider = self.td['PREFERRED_PROVIDER_virtual/kernel']
2006
Andrew Geissler82c905d2020-04-13 13:39:40 -05002007 # Clean up the environment
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002008 bitbake('%s -c clean' % kernel_provider)
2009 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
2010 tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
2011 self.track_for_cleanup(tempdir)
2012 self.track_for_cleanup(tempdir_cfg)
2013 self.track_for_cleanup(self.workspacedir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002014 self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
Brad Bishop00e122a2019-10-05 11:10:57 -04002015 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002016 #Step 1
2017 #Here is just generated the config file instead of all the kernel to optimize the
2018 #time of executing this test case.
2019 bitbake('%s -c configure' % kernel_provider)
2020 bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
2021 #Step 2
2022 runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
2023 self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
2024
2025 tmpconfig = os.path.join(tempdir_cfg, '.config')
2026 #Step 3
2027 bitbake('%s -c clean' % kernel_provider)
2028 #Step 4.1
2029 runCmd('devtool modify virtual/kernel -x %s' % tempdir)
2030 self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
2031 #Step 4.2
2032 configfile = os.path.join(tempdir,'.config')
Patrick Williams45852732022-04-02 08:58:32 -05002033 runCmd('diff %s %s' % (tmpconfig, configfile))
2034
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002035 #Step 4.3
2036 #NOTE: virtual/kernel is mapped to kernel_provider
Patrick Williams45852732022-04-02 08:58:32 -05002037 runCmd('devtool build %s' % kernel_provider)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002038 kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
2039 self.assertExists(kernelfile, 'Kernel was not build correctly')
2040
2041 #Modify the kernel source
Patrick Williams45852732022-04-02 08:58:32 -05002042 modfile = os.path.join(tempdir, 'init/version.c')
2043 runCmd("sed -i 's/Linux/LiNuX/g' %s" % (modfile))
2044
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002045 #Modify the configuration
Patrick Williams45852732022-04-02 08:58:32 -05002046 codeconfigfile = os.path.join(tempdir, '.config.new')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002047 modconfopt = "CONFIG_SG_POOL=n"
Patrick Williams45852732022-04-02 08:58:32 -05002048 runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
2049
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002050 #Build again kernel with devtool
Patrick Williams45852732022-04-02 08:58:32 -05002051 runCmd('devtool build %s' % kernel_provider)
2052
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002053 #Step 4.4
Patrick Williams45852732022-04-02 08:58:32 -05002054 runCmd("grep '%s' %s" % ('LiNuX', kernelfile))
2055
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002056 #Step 4.5
Patrick Williams45852732022-04-02 08:58:32 -05002057 runCmd("grep %s %s" % (modconfopt, codeconfigfile))