blob: 25b06cdcf0239e5b29a70674cf9cf536e6bcecf3 [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 shutil
9import tempfile
10import urllib.parse
11
12from oeqa.utils.commands import runCmd, bitbake, get_bb_var
13from oeqa.utils.commands import get_bb_vars, create_temp_layer
Brad Bishopd7bf8c12018-02-25 22:55:05 -050014from oeqa.selftest.cases import devtool
15
16templayerdir = None
17
18def setUpModule():
19 global templayerdir
20 templayerdir = tempfile.mkdtemp(prefix='recipetoolqa')
21 create_temp_layer(templayerdir, 'selftestrecipetool')
22 runCmd('bitbake-layers add-layer %s' % templayerdir)
23
24
25def tearDownModule():
26 runCmd('bitbake-layers remove-layer %s' % templayerdir, ignore_status=True)
27 runCmd('rm -rf %s' % templayerdir)
28
29
Andrew Geissler595f6302022-01-24 19:11:47 +000030class RecipetoolBase(devtool.DevtoolTestCase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050031
32 def setUpLocal(self):
33 super(RecipetoolBase, self).setUpLocal()
34 self.templayerdir = templayerdir
35 self.tempdir = tempfile.mkdtemp(prefix='recipetoolqa')
36 self.track_for_cleanup(self.tempdir)
37 self.testfile = os.path.join(self.tempdir, 'testfile')
38 with open(self.testfile, 'w') as f:
39 f.write('Test file\n')
40
41 def tearDownLocal(self):
42 runCmd('rm -rf %s/recipes-*' % self.templayerdir)
43 super(RecipetoolBase, self).tearDownLocal()
44
45 def _try_recipetool_appendcmd(self, cmd, testrecipe, expectedfiles, expectedlines=None):
46 result = runCmd(cmd)
47 self.assertNotIn('Traceback', result.output)
48
49 # Check the bbappend was created and applies properly
50 recipefile = get_bb_var('FILE', testrecipe)
51 bbappendfile = self._check_bbappend(testrecipe, recipefile, self.templayerdir)
52
53 # Check the bbappend contents
54 if expectedlines is not None:
55 with open(bbappendfile, 'r') as f:
56 self.assertEqual(expectedlines, f.readlines(), "Expected lines are not present in %s" % bbappendfile)
57
58 # Check file was copied
59 filesdir = os.path.join(os.path.dirname(bbappendfile), testrecipe)
60 for expectedfile in expectedfiles:
61 self.assertTrue(os.path.isfile(os.path.join(filesdir, expectedfile)), 'Expected file %s to be copied next to bbappend, but it wasn\'t' % expectedfile)
62
63 # Check no other files created
64 createdfiles = []
65 for root, _, files in os.walk(filesdir):
66 for f in files:
67 createdfiles.append(os.path.relpath(os.path.join(root, f), filesdir))
68 self.assertTrue(sorted(createdfiles), sorted(expectedfiles))
69
70 return bbappendfile, result.output
71
72
Andrew Geissler595f6302022-01-24 19:11:47 +000073class RecipetoolAppendTests(RecipetoolBase):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050074
75 @classmethod
76 def setUpClass(cls):
Andrew Geissler595f6302022-01-24 19:11:47 +000077 super(RecipetoolAppendTests, cls).setUpClass()
Brad Bishopd7bf8c12018-02-25 22:55:05 -050078 # Ensure we have the right data in shlibs/pkgdata
79 cls.logger.info('Running bitbake to generate pkgdata')
80 bitbake('-c packagedata base-files coreutils busybox selftest-recipetool-appendfile')
Andrew Geissler595f6302022-01-24 19:11:47 +000081 bb_vars = get_bb_vars(['COREBASE'])
Brad Bishopd7bf8c12018-02-25 22:55:05 -050082 cls.corebase = bb_vars['COREBASE']
Brad Bishopd7bf8c12018-02-25 22:55:05 -050083
84 def _try_recipetool_appendfile(self, testrecipe, destfile, newfile, options, expectedlines, expectedfiles):
85 cmd = 'recipetool appendfile %s %s %s %s' % (self.templayerdir, destfile, newfile, options)
86 return self._try_recipetool_appendcmd(cmd, testrecipe, expectedfiles, expectedlines)
87
88 def _try_recipetool_appendfile_fail(self, destfile, newfile, checkerror):
89 cmd = 'recipetool appendfile %s %s %s' % (self.templayerdir, destfile, newfile)
90 result = runCmd(cmd, ignore_status=True)
91 self.assertNotEqual(result.status, 0, 'Command "%s" should have failed but didn\'t' % cmd)
92 self.assertNotIn('Traceback', result.output)
93 for errorstr in checkerror:
94 self.assertIn(errorstr, result.output)
95
Brad Bishopd7bf8c12018-02-25 22:55:05 -050096 def test_recipetool_appendfile_basic(self):
97 # Basic test
Patrick Williams213cb262021-08-07 19:21:33 -050098 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -050099 '\n']
100 _, output = self._try_recipetool_appendfile('base-files', '/etc/motd', self.testfile, '', expectedlines, ['motd'])
101 self.assertNotIn('WARNING: ', output)
102
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500103 def test_recipetool_appendfile_invalid(self):
104 # Test some commands that should error
105 self._try_recipetool_appendfile_fail('/etc/passwd', self.testfile, ['ERROR: /etc/passwd cannot be handled by this tool', 'useradd', 'extrausers'])
106 self._try_recipetool_appendfile_fail('/etc/timestamp', self.testfile, ['ERROR: /etc/timestamp cannot be handled by this tool'])
107 self._try_recipetool_appendfile_fail('/dev/console', self.testfile, ['ERROR: /dev/console cannot be handled by this tool'])
108
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500109 def test_recipetool_appendfile_alternatives(self):
110 # Now try with a file we know should be an alternative
111 # (this is very much a fake example, but one we know is reliably an alternative)
112 self._try_recipetool_appendfile_fail('/bin/ls', self.testfile, ['ERROR: File /bin/ls is an alternative possibly provided by the following recipes:', 'coreutils', 'busybox'])
113 # Need a test file - should be executable
114 testfile2 = os.path.join(self.corebase, 'oe-init-build-env')
115 testfile2name = os.path.basename(testfile2)
Patrick Williams213cb262021-08-07 19:21:33 -0500116 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500117 '\n',
118 'SRC_URI += "file://%s"\n' % testfile2name,
119 '\n',
Patrick Williams213cb262021-08-07 19:21:33 -0500120 'do_install:append() {\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500121 ' install -d ${D}${base_bindir}\n',
122 ' install -m 0755 ${WORKDIR}/%s ${D}${base_bindir}/ls\n' % testfile2name,
123 '}\n']
124 self._try_recipetool_appendfile('coreutils', '/bin/ls', testfile2, '-r coreutils', expectedlines, [testfile2name])
125 # Now try bbappending the same file again, contents should not change
126 bbappendfile, _ = self._try_recipetool_appendfile('coreutils', '/bin/ls', self.testfile, '-r coreutils', expectedlines, [testfile2name])
127 # But file should have
128 copiedfile = os.path.join(os.path.dirname(bbappendfile), 'coreutils', testfile2name)
129 result = runCmd('diff -q %s %s' % (testfile2, copiedfile), ignore_status=True)
130 self.assertNotEqual(result.status, 0, 'New file should have been copied but was not %s' % result.output)
131
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500132 def test_recipetool_appendfile_binary(self):
133 # Try appending a binary file
134 # /bin/ls can be a symlink to /usr/bin/ls
135 ls = os.path.realpath("/bin/ls")
136 result = runCmd('recipetool appendfile %s /bin/ls %s -r coreutils' % (self.templayerdir, ls))
137 self.assertIn('WARNING: ', result.output)
138 self.assertIn('is a binary', result.output)
139
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500140 def test_recipetool_appendfile_add(self):
141 # Try arbitrary file add to a recipe
Patrick Williams213cb262021-08-07 19:21:33 -0500142 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500143 '\n',
144 'SRC_URI += "file://testfile"\n',
145 '\n',
Patrick Williams213cb262021-08-07 19:21:33 -0500146 'do_install:append() {\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500147 ' install -d ${D}${datadir}\n',
148 ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/something\n',
149 '}\n']
150 self._try_recipetool_appendfile('netbase', '/usr/share/something', self.testfile, '-r netbase', expectedlines, ['testfile'])
151 # Try adding another file, this time where the source file is executable
152 # (so we're testing that, plus modifying an existing bbappend)
153 testfile2 = os.path.join(self.corebase, 'oe-init-build-env')
154 testfile2name = os.path.basename(testfile2)
Patrick Williams213cb262021-08-07 19:21:33 -0500155 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500156 '\n',
157 'SRC_URI += "file://testfile \\\n',
158 ' file://%s \\\n' % testfile2name,
159 ' "\n',
160 '\n',
Patrick Williams213cb262021-08-07 19:21:33 -0500161 'do_install:append() {\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500162 ' install -d ${D}${datadir}\n',
163 ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/something\n',
164 ' install -m 0755 ${WORKDIR}/%s ${D}${datadir}/scriptname\n' % testfile2name,
165 '}\n']
166 self._try_recipetool_appendfile('netbase', '/usr/share/scriptname', testfile2, '-r netbase', expectedlines, ['testfile', testfile2name])
167
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500168 def test_recipetool_appendfile_add_bindir(self):
169 # Try arbitrary file add to a recipe, this time to a location such that should be installed as executable
Patrick Williams213cb262021-08-07 19:21:33 -0500170 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500171 '\n',
172 'SRC_URI += "file://testfile"\n',
173 '\n',
Patrick Williams213cb262021-08-07 19:21:33 -0500174 'do_install:append() {\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500175 ' install -d ${D}${bindir}\n',
176 ' install -m 0755 ${WORKDIR}/testfile ${D}${bindir}/selftest-recipetool-testbin\n',
177 '}\n']
178 _, output = self._try_recipetool_appendfile('netbase', '/usr/bin/selftest-recipetool-testbin', self.testfile, '-r netbase', expectedlines, ['testfile'])
179 self.assertNotIn('WARNING: ', output)
180
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500181 def test_recipetool_appendfile_add_machine(self):
182 # Try arbitrary file add to a recipe, this time to a location such that should be installed as executable
Patrick Williams213cb262021-08-07 19:21:33 -0500183 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500184 '\n',
185 'PACKAGE_ARCH = "${MACHINE_ARCH}"\n',
186 '\n',
Patrick Williams213cb262021-08-07 19:21:33 -0500187 'SRC_URI:append:mymachine = " file://testfile"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500188 '\n',
Patrick Williams213cb262021-08-07 19:21:33 -0500189 'do_install:append:mymachine() {\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500190 ' install -d ${D}${datadir}\n',
191 ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/something\n',
192 '}\n']
193 _, output = self._try_recipetool_appendfile('netbase', '/usr/share/something', self.testfile, '-r netbase -m mymachine', expectedlines, ['mymachine/testfile'])
194 self.assertNotIn('WARNING: ', output)
195
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500196 def test_recipetool_appendfile_orig(self):
197 # A file that's in SRC_URI and in do_install with the same name
Patrick Williams213cb262021-08-07 19:21:33 -0500198 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500199 '\n']
200 _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-orig', self.testfile, '', expectedlines, ['selftest-replaceme-orig'])
201 self.assertNotIn('WARNING: ', output)
202
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500203 def test_recipetool_appendfile_todir(self):
204 # A file that's in SRC_URI and in do_install with destination directory rather than file
Patrick Williams213cb262021-08-07 19:21:33 -0500205 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500206 '\n']
207 _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-todir', self.testfile, '', expectedlines, ['selftest-replaceme-todir'])
208 self.assertNotIn('WARNING: ', output)
209
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500210 def test_recipetool_appendfile_renamed(self):
211 # A file that's in SRC_URI with a different name to the destination file
Patrick Williams213cb262021-08-07 19:21:33 -0500212 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500213 '\n']
214 _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-renamed', self.testfile, '', expectedlines, ['file1'])
215 self.assertNotIn('WARNING: ', output)
216
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500217 def test_recipetool_appendfile_subdir(self):
218 # A file that's in SRC_URI in a subdir
Patrick Williams213cb262021-08-07 19:21:33 -0500219 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500220 '\n',
221 'SRC_URI += "file://testfile"\n',
222 '\n',
Patrick Williams213cb262021-08-07 19:21:33 -0500223 'do_install:append() {\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500224 ' install -d ${D}${datadir}\n',
225 ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/selftest-replaceme-subdir\n',
226 '}\n']
227 _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-subdir', self.testfile, '', expectedlines, ['testfile'])
228 self.assertNotIn('WARNING: ', output)
229
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500230 def test_recipetool_appendfile_inst_glob(self):
231 # A file that's in do_install as a glob
Patrick Williams213cb262021-08-07 19:21:33 -0500232 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500233 '\n']
234 _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-inst-globfile', self.testfile, '', expectedlines, ['selftest-replaceme-inst-globfile'])
235 self.assertNotIn('WARNING: ', output)
236
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500237 def test_recipetool_appendfile_inst_todir_glob(self):
238 # A file that's in do_install as a glob with destination as a directory
Patrick Williams213cb262021-08-07 19:21:33 -0500239 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500240 '\n']
241 _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-inst-todir-globfile', self.testfile, '', expectedlines, ['selftest-replaceme-inst-todir-globfile'])
242 self.assertNotIn('WARNING: ', output)
243
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500244 def test_recipetool_appendfile_patch(self):
245 # A file that's added by a patch in SRC_URI
Patrick Williams213cb262021-08-07 19:21:33 -0500246 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500247 '\n',
248 'SRC_URI += "file://testfile"\n',
249 '\n',
Patrick Williams213cb262021-08-07 19:21:33 -0500250 'do_install:append() {\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500251 ' install -d ${D}${sysconfdir}\n',
252 ' install -m 0644 ${WORKDIR}/testfile ${D}${sysconfdir}/selftest-replaceme-patched\n',
253 '}\n']
254 _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/etc/selftest-replaceme-patched', self.testfile, '', expectedlines, ['testfile'])
255 for line in output.splitlines():
256 if 'WARNING: ' in line:
257 self.assertIn('add-file.patch', line, 'Unexpected warning found in output:\n%s' % line)
258 break
259 else:
260 self.fail('Patch warning not found in output:\n%s' % output)
261
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500262 def test_recipetool_appendfile_script(self):
263 # Now, a file that's in SRC_URI but installed by a script (so no mention in do_install)
Patrick Williams213cb262021-08-07 19:21:33 -0500264 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500265 '\n',
266 'SRC_URI += "file://testfile"\n',
267 '\n',
Patrick Williams213cb262021-08-07 19:21:33 -0500268 'do_install:append() {\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500269 ' install -d ${D}${datadir}\n',
270 ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/selftest-replaceme-scripted\n',
271 '}\n']
272 _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-scripted', self.testfile, '', expectedlines, ['testfile'])
273 self.assertNotIn('WARNING: ', output)
274
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500275 def test_recipetool_appendfile_inst_func(self):
276 # A file that's installed from a function called by do_install
Patrick Williams213cb262021-08-07 19:21:33 -0500277 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500278 '\n']
279 _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-inst-func', self.testfile, '', expectedlines, ['selftest-replaceme-inst-func'])
280 self.assertNotIn('WARNING: ', output)
281
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500282 def test_recipetool_appendfile_postinstall(self):
283 # A file that's created by a postinstall script (and explicitly mentioned in it)
284 # First try without specifying recipe
285 self._try_recipetool_appendfile_fail('/usr/share/selftest-replaceme-postinst', self.testfile, ['File /usr/share/selftest-replaceme-postinst may be written out in a pre/postinstall script of the following recipes:', 'selftest-recipetool-appendfile'])
286 # Now specify recipe
Patrick Williams213cb262021-08-07 19:21:33 -0500287 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500288 '\n',
289 'SRC_URI += "file://testfile"\n',
290 '\n',
Patrick Williams213cb262021-08-07 19:21:33 -0500291 'do_install:append() {\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500292 ' install -d ${D}${datadir}\n',
293 ' install -m 0644 ${WORKDIR}/testfile ${D}${datadir}/selftest-replaceme-postinst\n',
294 '}\n']
295 _, output = self._try_recipetool_appendfile('selftest-recipetool-appendfile', '/usr/share/selftest-replaceme-postinst', self.testfile, '-r selftest-recipetool-appendfile', expectedlines, ['testfile'])
296
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500297 def test_recipetool_appendfile_extlayer(self):
298 # Try creating a bbappend in a layer that's not in bblayers.conf and has a different structure
299 exttemplayerdir = os.path.join(self.tempdir, 'extlayer')
300 self._create_temp_layer(exttemplayerdir, False, 'oeselftestextlayer', recipepathspec='metadata/recipes/recipes-*/*')
301 result = runCmd('recipetool appendfile %s /usr/share/selftest-replaceme-orig %s' % (exttemplayerdir, self.testfile))
302 self.assertNotIn('Traceback', result.output)
303 createdfiles = []
304 for root, _, files in os.walk(exttemplayerdir):
305 for f in files:
306 createdfiles.append(os.path.relpath(os.path.join(root, f), exttemplayerdir))
307 createdfiles.remove('conf/layer.conf')
308 expectedfiles = ['metadata/recipes/recipes-test/selftest-recipetool-appendfile/selftest-recipetool-appendfile.bbappend',
309 'metadata/recipes/recipes-test/selftest-recipetool-appendfile/selftest-recipetool-appendfile/selftest-replaceme-orig']
310 self.assertEqual(sorted(createdfiles), sorted(expectedfiles))
311
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500312 def test_recipetool_appendfile_wildcard(self):
313
314 def try_appendfile_wc(options):
315 result = runCmd('recipetool appendfile %s /etc/profile %s %s' % (self.templayerdir, self.testfile, options))
316 self.assertNotIn('Traceback', result.output)
317 bbappendfile = None
318 for root, _, files in os.walk(self.templayerdir):
319 for f in files:
320 if f.endswith('.bbappend'):
321 bbappendfile = f
322 break
323 if not bbappendfile:
324 self.fail('No bbappend file created')
325 runCmd('rm -rf %s/recipes-*' % self.templayerdir)
326 return bbappendfile
327
328 # Check without wildcard option
329 recipefn = os.path.basename(get_bb_var('FILE', 'base-files'))
330 filename = try_appendfile_wc('')
331 self.assertEqual(filename, recipefn.replace('.bb', '.bbappend'))
332 # Now check with wildcard option
333 filename = try_appendfile_wc('-w')
334 self.assertEqual(filename, recipefn.split('_')[0] + '_%.bbappend')
335
Andrew Geissler595f6302022-01-24 19:11:47 +0000336
337class RecipetoolCreateTests(RecipetoolBase):
338
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500339 def test_recipetool_create(self):
340 # Try adding a recipe
341 tempsrc = os.path.join(self.tempdir, 'srctree')
342 os.makedirs(tempsrc)
343 recipefile = os.path.join(self.tempdir, 'logrotate_3.12.3.bb')
344 srcuri = 'https://github.com/logrotate/logrotate/releases/download/3.12.3/logrotate-3.12.3.tar.xz'
345 result = runCmd('recipetool create -o %s %s -x %s' % (recipefile, srcuri, tempsrc))
346 self.assertTrue(os.path.isfile(recipefile))
347 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000348 checkvars['LICENSE'] = 'GPL-2.0-only'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500349 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
350 checkvars['SRC_URI'] = 'https://github.com/logrotate/logrotate/releases/download/${PV}/logrotate-${PV}.tar.xz'
351 checkvars['SRC_URI[md5sum]'] = 'a560c57fac87c45b2fc17406cdf79288'
352 checkvars['SRC_URI[sha256sum]'] = '2e6a401cac9024db2288297e3be1a8ab60e7401ba8e91225218aaf4a27e82a07'
353 self._test_recipe_contents(recipefile, checkvars, [])
354
Andrew Geissler595f6302022-01-24 19:11:47 +0000355 def test_recipetool_create_autotools(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500356 if 'x11' not in get_bb_var('DISTRO_FEATURES'):
357 self.skipTest('Test requires x11 as distro feature')
358 # Ensure we have the right data in shlibs/pkgdata
359 bitbake('libpng pango libx11 libxext jpeg libcheck')
360 # Try adding a recipe
361 tempsrc = os.path.join(self.tempdir, 'srctree')
362 os.makedirs(tempsrc)
363 recipefile = os.path.join(self.tempdir, 'libmatchbox.bb')
364 srcuri = 'git://git.yoctoproject.org/libmatchbox'
365 result = runCmd(['recipetool', 'create', '-o', recipefile, srcuri + ";rev=9f7cf8895ae2d39c465c04cc78e918c157420269", '-x', tempsrc])
366 self.assertTrue(os.path.isfile(recipefile), 'recipetool did not create recipe file; output:\n%s' % result.output)
367 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000368 checkvars['LICENSE'] = 'LGPL-2.1-only'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500369 checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=7fbc338309ac38fefcd64b04bb903e34'
370 checkvars['S'] = '${WORKDIR}/git'
371 checkvars['PV'] = '1.11+git${SRCPV}'
Andrew Geissler595f6302022-01-24 19:11:47 +0000372 checkvars['SRC_URI'] = srcuri + ';branch=master'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500373 checkvars['DEPENDS'] = set(['libcheck', 'libjpeg-turbo', 'libpng', 'libx11', 'libxext', 'pango'])
374 inherits = ['autotools', 'pkgconfig']
375 self._test_recipe_contents(recipefile, checkvars, inherits)
376
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500377 def test_recipetool_create_simple(self):
378 # Try adding a recipe
379 temprecipe = os.path.join(self.tempdir, 'recipe')
380 os.makedirs(temprecipe)
Andrew Geissler5f350902021-07-23 13:09:54 -0400381 pv = '1.7.4.1'
Andrew Geissler9aee5002022-03-30 16:27:02 +0000382 srcuri = 'http://www.dest-unreach.org/socat/download/Archive/socat-%s.tar.bz2' % pv
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500383 result = runCmd('recipetool create %s -o %s' % (srcuri, temprecipe))
384 dirlist = os.listdir(temprecipe)
385 if len(dirlist) > 1:
386 self.fail('recipetool created more than just one file; output:\n%s\ndirlist:\n%s' % (result.output, str(dirlist)))
387 if len(dirlist) < 1 or not os.path.isfile(os.path.join(temprecipe, dirlist[0])):
388 self.fail('recipetool did not create recipe file; output:\n%s\ndirlist:\n%s' % (result.output, str(dirlist)))
389 self.assertEqual(dirlist[0], 'socat_%s.bb' % pv, 'Recipe file incorrectly named')
390 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000391 checkvars['LICENSE'] = set(['Unknown', 'GPL-2.0-only'])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500392 checkvars['LIC_FILES_CHKSUM'] = set(['file://COPYING.OpenSSL;md5=5c9bccc77f67a8328ef4ebaf468116f4', 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'])
393 # We don't check DEPENDS since they are variable for this recipe depending on what's in the sysroot
394 checkvars['S'] = None
395 checkvars['SRC_URI'] = srcuri.replace(pv, '${PV}')
396 inherits = ['autotools']
397 self._test_recipe_contents(os.path.join(temprecipe, dirlist[0]), checkvars, inherits)
398
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500399 def test_recipetool_create_cmake(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500400 temprecipe = os.path.join(self.tempdir, 'recipe')
401 os.makedirs(temprecipe)
Brad Bishop96ff1982019-08-19 13:50:42 -0400402 recipefile = os.path.join(temprecipe, 'taglib_1.11.1.bb')
403 srcuri = 'http://taglib.github.io/releases/taglib-1.11.1.tar.gz'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500404 result = runCmd('recipetool create -o %s %s' % (temprecipe, srcuri))
405 self.assertTrue(os.path.isfile(recipefile))
406 checkvars = {}
Andrew Geissler9aee5002022-03-30 16:27:02 +0000407 checkvars['LICENSE'] = set(['LGPL-2.1-only', 'MPL-1.1-only'])
Brad Bishop96ff1982019-08-19 13:50:42 -0400408 checkvars['SRC_URI'] = 'http://taglib.github.io/releases/taglib-${PV}.tar.gz'
409 checkvars['SRC_URI[md5sum]'] = 'cee7be0ccfc892fa433d6c837df9522a'
410 checkvars['SRC_URI[sha256sum]'] = 'b6d1a5a610aae6ff39d93de5efd0fdc787aa9e9dc1e7026fa4c961b26563526b'
411 checkvars['DEPENDS'] = set(['boost', 'zlib'])
412 inherits = ['cmake']
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500413 self._test_recipe_contents(recipefile, checkvars, inherits)
414
Andrew Geissler82c905d2020-04-13 13:39:40 -0500415 def test_recipetool_create_npm(self):
Andrew Geisslerf0343792020-11-18 10:42:21 -0600416 collections = get_bb_var('BBFILE_COLLECTIONS').split()
417 if "openembedded-layer" not in collections:
418 self.skipTest("Test needs meta-oe for nodejs")
419
Andrew Geissler82c905d2020-04-13 13:39:40 -0500420 temprecipe = os.path.join(self.tempdir, 'recipe')
421 os.makedirs(temprecipe)
422 recipefile = os.path.join(temprecipe, 'savoirfairelinux-node-server-example_1.0.0.bb')
423 shrinkwrap = os.path.join(temprecipe, 'savoirfairelinux-node-server-example', 'npm-shrinkwrap.json')
424 srcuri = 'npm://registry.npmjs.org;package=@savoirfairelinux/node-server-example;version=1.0.0'
425 result = runCmd('recipetool create -o %s \'%s\'' % (temprecipe, srcuri))
426 self.assertTrue(os.path.isfile(recipefile))
427 self.assertTrue(os.path.isfile(shrinkwrap))
428 checkvars = {}
429 checkvars['SUMMARY'] = 'Node Server Example'
430 checkvars['HOMEPAGE'] = 'https://github.com/savoirfairelinux/node-server-example#readme'
Andrew Geissler595f6302022-01-24 19:11:47 +0000431 checkvars['LICENSE'] = 'BSD-3-Clause & ISC & MIT & Unknown'
Andrew Geissler82c905d2020-04-13 13:39:40 -0500432 urls = []
433 urls.append('npm://registry.npmjs.org/;package=@savoirfairelinux/node-server-example;version=${PV}')
434 urls.append('npmsw://${THISDIR}/${BPN}/npm-shrinkwrap.json')
435 checkvars['SRC_URI'] = set(urls)
436 checkvars['S'] = '${WORKDIR}/npm'
Patrick Williams213cb262021-08-07 19:21:33 -0500437 checkvars['LICENSE:${PN}'] = 'MIT'
438 checkvars['LICENSE:${PN}-base64'] = 'Unknown'
439 checkvars['LICENSE:${PN}-accepts'] = 'MIT'
440 checkvars['LICENSE:${PN}-inherits'] = 'ISC'
Andrew Geissler82c905d2020-04-13 13:39:40 -0500441 inherits = ['npm']
442 self._test_recipe_contents(recipefile, checkvars, inherits)
443
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500444 def test_recipetool_create_github(self):
445 # Basic test to see if github URL mangling works
446 temprecipe = os.path.join(self.tempdir, 'recipe')
447 os.makedirs(temprecipe)
448 recipefile = os.path.join(temprecipe, 'meson_git.bb')
449 srcuri = 'https://github.com/mesonbuild/meson;rev=0.32.0'
450 result = runCmd(['recipetool', 'create', '-o', temprecipe, srcuri])
451 self.assertTrue(os.path.isfile(recipefile))
452 checkvars = {}
453 checkvars['LICENSE'] = set(['Apache-2.0'])
Andrew Geissler595f6302022-01-24 19:11:47 +0000454 checkvars['SRC_URI'] = 'git://github.com/mesonbuild/meson;protocol=https;branch=master'
Brad Bishop15ae2502019-06-18 21:44:24 -0400455 inherits = ['setuptools3']
456 self._test_recipe_contents(recipefile, checkvars, inherits)
457
458 def test_recipetool_create_python3_setuptools(self):
459 # Test creating python3 package from tarball (using setuptools3 class)
460 temprecipe = os.path.join(self.tempdir, 'recipe')
461 os.makedirs(temprecipe)
462 pn = 'python-magic'
463 pv = '0.4.15'
464 recipefile = os.path.join(temprecipe, '%s_%s.bb' % (pn, pv))
465 srcuri = 'https://files.pythonhosted.org/packages/84/30/80932401906eaf787f2e9bd86dc458f1d2e75b064b4c187341f29516945c/python-magic-%s.tar.gz' % pv
466 result = runCmd('recipetool create -o %s %s' % (temprecipe, srcuri))
467 self.assertTrue(os.path.isfile(recipefile))
468 checkvars = {}
469 checkvars['LICENSE'] = set(['MIT'])
470 checkvars['LIC_FILES_CHKSUM'] = 'file://LICENSE;md5=16a934f165e8c3245f241e77d401bb88'
471 checkvars['SRC_URI'] = 'https://files.pythonhosted.org/packages/84/30/80932401906eaf787f2e9bd86dc458f1d2e75b064b4c187341f29516945c/python-magic-${PV}.tar.gz'
472 checkvars['SRC_URI[md5sum]'] = 'e384c95a47218f66c6501cd6dd45ff59'
473 checkvars['SRC_URI[sha256sum]'] = 'f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5'
474 inherits = ['setuptools3']
475 self._test_recipe_contents(recipefile, checkvars, inherits)
476
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500477 def test_recipetool_create_github_tarball(self):
478 # Basic test to ensure github URL mangling doesn't apply to release tarballs
479 temprecipe = os.path.join(self.tempdir, 'recipe')
480 os.makedirs(temprecipe)
481 pv = '0.32.0'
482 recipefile = os.path.join(temprecipe, 'meson_%s.bb' % pv)
483 srcuri = 'https://github.com/mesonbuild/meson/releases/download/%s/meson-%s.tar.gz' % (pv, pv)
484 result = runCmd('recipetool create -o %s %s' % (temprecipe, srcuri))
485 self.assertTrue(os.path.isfile(recipefile))
486 checkvars = {}
487 checkvars['LICENSE'] = set(['Apache-2.0'])
488 checkvars['SRC_URI'] = 'https://github.com/mesonbuild/meson/releases/download/${PV}/meson-${PV}.tar.gz'
Brad Bishop15ae2502019-06-18 21:44:24 -0400489 inherits = ['setuptools3']
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500490 self._test_recipe_contents(recipefile, checkvars, inherits)
491
Andrew Geissler595f6302022-01-24 19:11:47 +0000492 def _test_recipetool_create_git(self, srcuri, branch=None):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500493 # Basic test to check http git URL mangling works
494 temprecipe = os.path.join(self.tempdir, 'recipe')
495 os.makedirs(temprecipe)
Andrew Geissler595f6302022-01-24 19:11:47 +0000496 name = srcuri.split(';')[0].split('/')[-1]
497 recipefile = os.path.join(temprecipe, name + '_git.bb')
498 options = ' -B %s' % branch if branch else ''
499 result = runCmd('recipetool create -o %s%s "%s"' % (temprecipe, options, srcuri))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500500 self.assertTrue(os.path.isfile(recipefile))
501 checkvars = {}
Andrew Geissler595f6302022-01-24 19:11:47 +0000502 checkvars['SRC_URI'] = srcuri
503 for scheme in ['http', 'https']:
504 if srcuri.startswith(scheme + ":"):
505 checkvars['SRC_URI'] = 'git%s;protocol=%s' % (srcuri[len(scheme):], scheme)
506 if ';branch=' not in srcuri:
507 checkvars['SRC_URI'] += ';branch=' + (branch or 'master')
508 self._test_recipe_contents(recipefile, checkvars, [])
509
510 def test_recipetool_create_git_http(self):
511 self._test_recipetool_create_git('http://git.yoctoproject.org/git/matchbox-keyboard')
512
513 def test_recipetool_create_git_srcuri_master(self):
514 self._test_recipetool_create_git('git://git.yoctoproject.org/matchbox-keyboard;branch=master')
515
516 def test_recipetool_create_git_srcuri_branch(self):
517 self._test_recipetool_create_git('git://git.yoctoproject.org/matchbox-keyboard;branch=matchbox-keyboard-0-1')
518
519 def test_recipetool_create_git_srcbranch(self):
520 self._test_recipetool_create_git('git://git.yoctoproject.org/matchbox-keyboard', 'matchbox-keyboard-0-1')
521
522
523class RecipetoolTests(RecipetoolBase):
524
525 @classmethod
526 def setUpClass(cls):
527 import sys
528
529 super(RecipetoolTests, cls).setUpClass()
530 bb_vars = get_bb_vars(['BBPATH'])
531 cls.bbpath = bb_vars['BBPATH']
532 libpath = os.path.join(get_bb_var('COREBASE'), 'scripts', 'lib', 'recipetool')
533 sys.path.insert(0, libpath)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500534
535 def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
536 dstdir = basedstdir
537 self.assertTrue(os.path.exists(dstdir))
538 for p in paths:
539 dstdir = os.path.join(dstdir, p)
540 if not os.path.exists(dstdir):
541 os.makedirs(dstdir)
Andrew Geissler475cb722020-07-10 16:00:51 -0500542 if p == "lib":
543 # Can race with other tests
544 self.add_command_to_tearDown('rmdir --ignore-fail-on-non-empty %s' % dstdir)
545 else:
546 self.track_for_cleanup(dstdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500547 dstfile = os.path.join(dstdir, os.path.basename(srcfile))
548 if srcfile != dstfile:
549 shutil.copy(srcfile, dstfile)
550 self.track_for_cleanup(dstfile)
551
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500552 def test_recipetool_load_plugin(self):
553 """Test that recipetool loads only the first found plugin in BBPATH."""
554
555 recipetool = runCmd("which recipetool")
556 fromname = runCmd("recipetool --quiet pluginfile")
557 srcfile = fromname.output
558 searchpath = self.bbpath.split(':') + [os.path.dirname(recipetool.output)]
559 plugincontent = []
560 with open(srcfile) as fh:
561 plugincontent = fh.readlines()
562 try:
563 self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
564 for path in searchpath:
565 self._copy_file_with_cleanup(srcfile, path, 'lib', 'recipetool')
566 result = runCmd("recipetool --quiet count")
567 self.assertEqual(result.output, '1')
568 result = runCmd("recipetool --quiet multiloaded")
569 self.assertEqual(result.output, "no")
570 for path in searchpath:
571 result = runCmd("recipetool --quiet bbdir")
572 self.assertEqual(result.output, path)
573 os.unlink(os.path.join(result.output, 'lib', 'recipetool', 'bbpath.py'))
574 finally:
575 with open(srcfile, 'w') as fh:
576 fh.writelines(plugincontent)
577
Andrew Geissler595f6302022-01-24 19:11:47 +0000578 def test_recipetool_handle_license_vars(self):
579 from create import handle_license_vars
580 from unittest.mock import Mock
581
582 commonlicdir = get_bb_var('COMMON_LICENSE_DIR')
583
584 d = bb.tinfoil.TinfoilDataStoreConnector
585 d.getVar = Mock(return_value=commonlicdir)
586
587 srctree = tempfile.mkdtemp(prefix='recipetoolqa')
588 self.track_for_cleanup(srctree)
589
590 # Multiple licenses
591 licenses = ['MIT', 'ISC', 'BSD-3-Clause', 'Apache-2.0']
592 for licence in licenses:
593 shutil.copy(os.path.join(commonlicdir, licence), os.path.join(srctree, 'LICENSE.' + licence))
594 # Duplicate license
595 shutil.copy(os.path.join(commonlicdir, 'MIT'), os.path.join(srctree, 'LICENSE'))
596
597 extravalues = {
598 # Duplicate and missing licenses
599 'LICENSE': 'Zlib & BSD-2-Clause & Zlib',
600 'LIC_FILES_CHKSUM': [
601 'file://README.md;md5=0123456789abcdef0123456789abcd'
602 ]
603 }
604 lines_before = []
605 handled = []
606 licvalues = handle_license_vars(srctree, lines_before, handled, extravalues, d)
607 expected_lines_before = [
608 '# WARNING: the following LICENSE and LIC_FILES_CHKSUM values are best guesses - it is',
609 '# your responsibility to verify that the values are complete and correct.',
610 '# NOTE: Original package / source metadata indicates license is: BSD-2-Clause & Zlib',
611 '#',
612 '# NOTE: multiple licenses have been detected; they have been separated with &',
613 '# in the LICENSE value for now since it is a reasonable assumption that all',
614 '# of the licenses apply. If instead there is a choice between the multiple',
615 '# licenses then you should change the value to separate the licenses with |',
616 '# instead of &. If there is any doubt, check the accompanying documentation',
617 '# to determine which situation is applicable.',
618 'LICENSE = "Apache-2.0 & BSD-2-Clause & BSD-3-Clause & ISC & MIT & Zlib"',
619 'LIC_FILES_CHKSUM = "file://LICENSE;md5=0835ade698e0bcf8506ecda2f7b4f302 \\\n'
620 ' file://LICENSE.Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10 \\\n'
621 ' file://LICENSE.BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9 \\\n'
622 ' file://LICENSE.ISC;md5=f3b90e78ea0cffb20bf5cca7947a896d \\\n'
623 ' file://LICENSE.MIT;md5=0835ade698e0bcf8506ecda2f7b4f302 \\\n'
624 ' file://README.md;md5=0123456789abcdef0123456789abcd"',
625 ''
626 ]
627 self.assertEqual(lines_before, expected_lines_before)
628 expected_licvalues = [
629 ('MIT', 'LICENSE', '0835ade698e0bcf8506ecda2f7b4f302'),
630 ('Apache-2.0', 'LICENSE.Apache-2.0', '89aea4e17d99a7cacdbeed46a0096b10'),
631 ('BSD-3-Clause', 'LICENSE.BSD-3-Clause', '550794465ba0ec5312d6919e203a55f9'),
632 ('ISC', 'LICENSE.ISC', 'f3b90e78ea0cffb20bf5cca7947a896d'),
633 ('MIT', 'LICENSE.MIT', '0835ade698e0bcf8506ecda2f7b4f302')
634 ]
635 self.assertEqual(handled, [('license', expected_licvalues)])
636 self.assertEqual(extravalues, {})
637 self.assertEqual(licvalues, expected_licvalues)
638
639
640 def test_recipetool_split_pkg_licenses(self):
641 from create import split_pkg_licenses
642 licvalues = [
643 # Duplicate licenses
644 ('BSD-2-Clause', 'x/COPYING', None),
645 ('BSD-2-Clause', 'x/LICENSE', None),
646 # Multiple licenses
647 ('MIT', 'x/a/LICENSE.MIT', None),
648 ('ISC', 'x/a/LICENSE.ISC', None),
649 # Alternative licenses
650 ('(MIT | ISC)', 'x/b/LICENSE', None),
651 # Alternative licenses without brackets
652 ('MIT | BSD-2-Clause', 'x/c/LICENSE', None),
653 # Multi licenses with alternatives
654 ('MIT', 'x/d/COPYING', None),
655 ('MIT | BSD-2-Clause', 'x/d/LICENSE', None),
656 # Multi licenses with alternatives and brackets
657 ('Apache-2.0 & ((MIT | ISC) & BSD-3-Clause)', 'x/e/LICENSE', None)
658 ]
659 packages = {
660 '${PN}': '',
661 'a': 'x/a',
662 'b': 'x/b',
663 'c': 'x/c',
664 'd': 'x/d',
665 'e': 'x/e',
666 'f': 'x/f',
667 'g': 'x/g',
668 }
669 fallback_licenses = {
670 # Ignored
671 'a': 'BSD-3-Clause',
672 # Used
673 'f': 'BSD-3-Clause'
674 }
675 outlines = []
676 outlicenses = split_pkg_licenses(licvalues, packages, outlines, fallback_licenses)
677 expected_outlicenses = {
678 '${PN}': ['BSD-2-Clause'],
679 'a': ['ISC', 'MIT'],
680 'b': ['(ISC | MIT)'],
681 'c': ['(BSD-2-Clause | MIT)'],
682 'd': ['(BSD-2-Clause | MIT)', 'MIT'],
683 'e': ['(ISC | MIT)', 'Apache-2.0', 'BSD-3-Clause'],
684 'f': ['BSD-3-Clause'],
685 'g': ['Unknown']
686 }
687 self.assertEqual(outlicenses, expected_outlicenses)
688 expected_outlines = [
689 'LICENSE:${PN} = "BSD-2-Clause"',
690 'LICENSE:a = "ISC & MIT"',
691 'LICENSE:b = "(ISC | MIT)"',
692 'LICENSE:c = "(BSD-2-Clause | MIT)"',
693 'LICENSE:d = "(BSD-2-Clause | MIT) & MIT"',
694 'LICENSE:e = "(ISC | MIT) & Apache-2.0 & BSD-3-Clause"',
695 'LICENSE:f = "BSD-3-Clause"',
696 'LICENSE:g = "Unknown"'
697 ]
698 self.assertEqual(outlines, expected_outlines)
699
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500700
701class RecipetoolAppendsrcBase(RecipetoolBase):
702 def _try_recipetool_appendsrcfile(self, testrecipe, newfile, destfile, options, expectedlines, expectedfiles):
703 cmd = 'recipetool appendsrcfile %s %s %s %s %s' % (options, self.templayerdir, testrecipe, newfile, destfile)
704 return self._try_recipetool_appendcmd(cmd, testrecipe, expectedfiles, expectedlines)
705
706 def _try_recipetool_appendsrcfiles(self, testrecipe, newfiles, expectedlines=None, expectedfiles=None, destdir=None, options=''):
707
708 if destdir:
709 options += ' -D %s' % destdir
710
711 if expectedfiles is None:
712 expectedfiles = [os.path.basename(f) for f in newfiles]
713
714 cmd = 'recipetool appendsrcfiles %s %s %s %s' % (options, self.templayerdir, testrecipe, ' '.join(newfiles))
715 return self._try_recipetool_appendcmd(cmd, testrecipe, expectedfiles, expectedlines)
716
717 def _try_recipetool_appendsrcfile_fail(self, testrecipe, newfile, destfile, checkerror):
718 cmd = 'recipetool appendsrcfile %s %s %s %s' % (self.templayerdir, testrecipe, newfile, destfile or '')
719 result = runCmd(cmd, ignore_status=True)
720 self.assertNotEqual(result.status, 0, 'Command "%s" should have failed but didn\'t' % cmd)
721 self.assertNotIn('Traceback', result.output)
722 for errorstr in checkerror:
723 self.assertIn(errorstr, result.output)
724
725 @staticmethod
726 def _get_first_file_uri(recipe):
727 '''Return the first file:// in SRC_URI for the specified recipe.'''
728 src_uri = get_bb_var('SRC_URI', recipe).split()
729 for uri in src_uri:
730 p = urllib.parse.urlparse(uri)
731 if p.scheme == 'file':
732 return p.netloc + p.path
733
734 def _test_appendsrcfile(self, testrecipe, filename=None, destdir=None, has_src_uri=True, srcdir=None, newfile=None, options=''):
735 if newfile is None:
736 newfile = self.testfile
737
738 if srcdir:
739 if destdir:
740 expected_subdir = os.path.join(srcdir, destdir)
741 else:
742 expected_subdir = srcdir
743 else:
744 options += " -W"
745 expected_subdir = destdir
746
747 if filename:
748 if destdir:
749 destpath = os.path.join(destdir, filename)
750 else:
751 destpath = filename
752 else:
753 filename = os.path.basename(newfile)
754 if destdir:
755 destpath = destdir + os.sep
756 else:
757 destpath = '.' + os.sep
758
Patrick Williams213cb262021-08-07 19:21:33 -0500759 expectedlines = ['FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n',
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500760 '\n']
761 if has_src_uri:
762 uri = 'file://%s' % filename
763 if expected_subdir:
764 uri += ';subdir=%s' % expected_subdir
765 expectedlines[0:0] = ['SRC_URI += "%s"\n' % uri,
766 '\n']
767
768 return self._try_recipetool_appendsrcfile(testrecipe, newfile, destpath, options, expectedlines, [filename])
769
770 def _test_appendsrcfiles(self, testrecipe, newfiles, expectedfiles=None, destdir=None, options=''):
771 if expectedfiles is None:
772 expectedfiles = [os.path.basename(n) for n in newfiles]
773
774 self._try_recipetool_appendsrcfiles(testrecipe, newfiles, expectedfiles=expectedfiles, destdir=destdir, options=options)
775
776 bb_vars = get_bb_vars(['SRC_URI', 'FILE', 'FILESEXTRAPATHS'], testrecipe)
777 src_uri = bb_vars['SRC_URI'].split()
778 for f in expectedfiles:
779 if destdir:
780 self.assertIn('file://%s;subdir=%s' % (f, destdir), src_uri)
781 else:
782 self.assertIn('file://%s' % f, src_uri)
783
784 recipefile = bb_vars['FILE']
785 bbappendfile = self._check_bbappend(testrecipe, recipefile, self.templayerdir)
786 filesdir = os.path.join(os.path.dirname(bbappendfile), testrecipe)
787 filesextrapaths = bb_vars['FILESEXTRAPATHS'].split(':')
788 self.assertIn(filesdir, filesextrapaths)
789
790
791
792
793class RecipetoolAppendsrcTests(RecipetoolAppendsrcBase):
794
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500795 def test_recipetool_appendsrcfile_basic(self):
796 self._test_appendsrcfile('base-files', 'a-file')
797
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500798 def test_recipetool_appendsrcfile_basic_wildcard(self):
799 testrecipe = 'base-files'
800 self._test_appendsrcfile(testrecipe, 'a-file', options='-w')
801 recipefile = get_bb_var('FILE', testrecipe)
802 bbappendfile = self._check_bbappend(testrecipe, recipefile, self.templayerdir)
803 self.assertEqual(os.path.basename(bbappendfile), '%s_%%.bbappend' % testrecipe)
804
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500805 def test_recipetool_appendsrcfile_subdir_basic(self):
806 self._test_appendsrcfile('base-files', 'a-file', 'tmp')
807
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500808 def test_recipetool_appendsrcfile_subdir_basic_dirdest(self):
809 self._test_appendsrcfile('base-files', destdir='tmp')
810
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500811 def test_recipetool_appendsrcfile_srcdir_basic(self):
812 testrecipe = 'bash'
813 bb_vars = get_bb_vars(['S', 'WORKDIR'], testrecipe)
814 srcdir = bb_vars['S']
815 workdir = bb_vars['WORKDIR']
816 subdir = os.path.relpath(srcdir, workdir)
817 self._test_appendsrcfile(testrecipe, 'a-file', srcdir=subdir)
818
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500819 def test_recipetool_appendsrcfile_existing_in_src_uri(self):
820 testrecipe = 'base-files'
821 filepath = self._get_first_file_uri(testrecipe)
822 self.assertTrue(filepath, 'Unable to test, no file:// uri found in SRC_URI for %s' % testrecipe)
823 self._test_appendsrcfile(testrecipe, filepath, has_src_uri=False)
824
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500825 def test_recipetool_appendsrcfile_existing_in_src_uri_diff_params(self):
826 testrecipe = 'base-files'
827 subdir = 'tmp'
828 filepath = self._get_first_file_uri(testrecipe)
829 self.assertTrue(filepath, 'Unable to test, no file:// uri found in SRC_URI for %s' % testrecipe)
830
831 output = self._test_appendsrcfile(testrecipe, filepath, subdir, has_src_uri=False)
832 self.assertTrue(any('with different parameters' in l for l in output))
833
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500834 def test_recipetool_appendsrcfile_replace_file_srcdir(self):
835 testrecipe = 'bash'
836 filepath = 'Makefile.in'
837 bb_vars = get_bb_vars(['S', 'WORKDIR'], testrecipe)
838 srcdir = bb_vars['S']
839 workdir = bb_vars['WORKDIR']
840 subdir = os.path.relpath(srcdir, workdir)
841
842 self._test_appendsrcfile(testrecipe, filepath, srcdir=subdir)
843 bitbake('%s:do_unpack' % testrecipe)
Brad Bishop64c979e2019-11-04 13:55:29 -0500844 with open(self.testfile, 'r') as testfile:
845 with open(os.path.join(srcdir, filepath), 'r') as makefilein:
846 self.assertEqual(testfile.read(), makefilein.read())
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500847
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500848 def test_recipetool_appendsrcfiles_basic(self, destdir=None):
849 newfiles = [self.testfile]
850 for i in range(1, 5):
851 testfile = os.path.join(self.tempdir, 'testfile%d' % i)
852 with open(testfile, 'w') as f:
853 f.write('Test file %d\n' % i)
854 newfiles.append(testfile)
855 self._test_appendsrcfiles('gcc', newfiles, destdir=destdir, options='-W')
856
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500857 def test_recipetool_appendsrcfiles_basic_subdir(self):
858 self.test_recipetool_appendsrcfiles_basic(destdir='testdir')