diff options
Diffstat (limited to 'meta/lib/oeqa/selftest/cases/devtool.py')
-rw-r--r-- | meta/lib/oeqa/selftest/cases/devtool.py | 1696 |
1 files changed, 1696 insertions, 0 deletions
diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py new file mode 100644 index 0000000000..75340d6d7b --- /dev/null +++ b/meta/lib/oeqa/selftest/cases/devtool.py | |||
@@ -0,0 +1,1696 @@ | |||
1 | import os | ||
2 | import re | ||
3 | import shutil | ||
4 | import tempfile | ||
5 | import glob | ||
6 | import fnmatch | ||
7 | |||
8 | import oeqa.utils.ftools as ftools | ||
9 | from oeqa.selftest.case import OESelftestTestCase | ||
10 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer | ||
11 | from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer | ||
12 | from oeqa.core.decorator.oeid import OETestID | ||
13 | |||
14 | class DevtoolBase(OESelftestTestCase): | ||
15 | |||
16 | def _test_recipe_contents(self, recipefile, checkvars, checkinherits): | ||
17 | with open(recipefile, 'r') as f: | ||
18 | invar = None | ||
19 | invalue = None | ||
20 | for line in f: | ||
21 | var = None | ||
22 | if invar: | ||
23 | value = line.strip().strip('"') | ||
24 | if value.endswith('\\'): | ||
25 | invalue += ' ' + value[:-1].strip() | ||
26 | continue | ||
27 | else: | ||
28 | invalue += ' ' + value.strip() | ||
29 | var = invar | ||
30 | value = invalue | ||
31 | invar = None | ||
32 | elif '=' in line: | ||
33 | splitline = line.split('=', 1) | ||
34 | var = splitline[0].rstrip() | ||
35 | value = splitline[1].strip().strip('"') | ||
36 | if value.endswith('\\'): | ||
37 | invalue = value[:-1].strip() | ||
38 | invar = var | ||
39 | continue | ||
40 | elif line.startswith('inherit '): | ||
41 | inherits = line.split()[1:] | ||
42 | |||
43 | if var and var in checkvars: | ||
44 | needvalue = checkvars.pop(var) | ||
45 | if needvalue is None: | ||
46 | self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value)) | ||
47 | if isinstance(needvalue, set): | ||
48 | if var == 'LICENSE': | ||
49 | value = set(value.split(' & ')) | ||
50 | else: | ||
51 | value = set(value.split()) | ||
52 | self.assertEqual(value, needvalue, 'values for %s do not match' % var) | ||
53 | |||
54 | |||
55 | missingvars = {} | ||
56 | for var, value in checkvars.items(): | ||
57 | if value is not None: | ||
58 | missingvars[var] = value | ||
59 | self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars) | ||
60 | |||
61 | for inherit in checkinherits: | ||
62 | self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit) | ||
63 | |||
64 | def _check_bbappend(self, testrecipe, recipefile, appenddir): | ||
65 | result = runCmd('bitbake-layers show-appends', cwd=self.builddir) | ||
66 | resultlines = result.output.splitlines() | ||
67 | inrecipe = False | ||
68 | bbappends = [] | ||
69 | bbappendfile = None | ||
70 | for line in resultlines: | ||
71 | if inrecipe: | ||
72 | if line.startswith(' '): | ||
73 | bbappends.append(line.strip()) | ||
74 | else: | ||
75 | break | ||
76 | elif line == '%s:' % os.path.basename(recipefile): | ||
77 | inrecipe = True | ||
78 | self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends))) | ||
79 | for bbappend in bbappends: | ||
80 | if bbappend.startswith(appenddir): | ||
81 | bbappendfile = bbappend | ||
82 | break | ||
83 | else: | ||
84 | self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe) | ||
85 | return bbappendfile | ||
86 | |||
87 | def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'): | ||
88 | create_temp_layer(templayerdir, templayername, priority, recipepathspec) | ||
89 | if addlayer: | ||
90 | self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir) | ||
91 | result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir) | ||
92 | |||
93 | def _process_ls_output(self, output): | ||
94 | """ | ||
95 | Convert ls -l output to a format we can reasonably compare from one context | ||
96 | to another (e.g. from host to target) | ||
97 | """ | ||
98 | filelist = [] | ||
99 | for line in output.splitlines(): | ||
100 | splitline = line.split() | ||
101 | if len(splitline) < 8: | ||
102 | self.fail('_process_ls_output: invalid output line: %s' % line) | ||
103 | # Remove trailing . on perms | ||
104 | splitline[0] = splitline[0].rstrip('.') | ||
105 | # Remove leading . on paths | ||
106 | splitline[-1] = splitline[-1].lstrip('.') | ||
107 | # Drop fields we don't want to compare | ||
108 | del splitline[7] | ||
109 | del splitline[6] | ||
110 | del splitline[5] | ||
111 | del splitline[4] | ||
112 | del splitline[1] | ||
113 | filelist.append(' '.join(splitline)) | ||
114 | return filelist | ||
115 | |||
116 | |||
117 | class DevtoolTests(DevtoolBase): | ||
118 | |||
119 | @classmethod | ||
120 | def setUpClass(cls): | ||
121 | super(DevtoolTests, cls).setUpClass() | ||
122 | bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR']) | ||
123 | cls.original_sstate = bb_vars['SSTATE_DIR'] | ||
124 | cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool') | ||
125 | cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate | ||
126 | cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n' | ||
127 | % cls.original_sstate) | ||
128 | |||
129 | @classmethod | ||
130 | def tearDownClass(cls): | ||
131 | cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate) | ||
132 | runCmd('rm -rf %s' % cls.devtool_sstate) | ||
133 | super(DevtoolTests, cls).tearDownClass() | ||
134 | |||
135 | def setUp(self): | ||
136 | """Test case setup function""" | ||
137 | super(DevtoolTests, self).setUp() | ||
138 | self.workspacedir = os.path.join(self.builddir, 'workspace') | ||
139 | self.assertTrue(not os.path.exists(self.workspacedir), | ||
140 | 'This test cannot be run with a workspace directory ' | ||
141 | 'under the build directory') | ||
142 | self.append_config(self.sstate_conf) | ||
143 | |||
144 | def _check_src_repo(self, repo_dir): | ||
145 | """Check srctree git repository""" | ||
146 | self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')), | ||
147 | 'git repository for external source tree not found') | ||
148 | result = runCmd('git status --porcelain', cwd=repo_dir) | ||
149 | self.assertEqual(result.output.strip(), "", | ||
150 | 'Created git repo is not clean') | ||
151 | result = runCmd('git symbolic-ref HEAD', cwd=repo_dir) | ||
152 | self.assertEqual(result.output.strip(), "refs/heads/devtool", | ||
153 | 'Wrong branch in git repo') | ||
154 | |||
155 | def _check_repo_status(self, repo_dir, expected_status): | ||
156 | """Check the worktree status of a repository""" | ||
157 | result = runCmd('git status . --porcelain', | ||
158 | cwd=repo_dir) | ||
159 | for line in result.output.splitlines(): | ||
160 | for ind, (f_status, fn_re) in enumerate(expected_status): | ||
161 | if re.match(fn_re, line[3:]): | ||
162 | if f_status != line[:2]: | ||
163 | self.fail('Unexpected status in line: %s' % line) | ||
164 | expected_status.pop(ind) | ||
165 | break | ||
166 | else: | ||
167 | self.fail('Unexpected modified file in line: %s' % line) | ||
168 | if expected_status: | ||
169 | self.fail('Missing file changes: %s' % expected_status) | ||
170 | |||
171 | @OETestID(1158) | ||
172 | def test_create_workspace(self): | ||
173 | # Check preconditions | ||
174 | result = runCmd('bitbake-layers show-layers') | ||
175 | self.assertTrue('/workspace' not in result.output, 'This test cannot be run with a workspace layer in bblayers.conf') | ||
176 | # Try creating a workspace layer with a specific path | ||
177 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
178 | self.track_for_cleanup(tempdir) | ||
179 | result = runCmd('devtool create-workspace %s' % tempdir) | ||
180 | self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output) | ||
181 | result = runCmd('bitbake-layers show-layers') | ||
182 | self.assertIn(tempdir, result.output) | ||
183 | # Try creating a workspace layer with the default path | ||
184 | self.track_for_cleanup(self.workspacedir) | ||
185 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
186 | result = runCmd('devtool create-workspace') | ||
187 | self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output) | ||
188 | result = runCmd('bitbake-layers show-layers') | ||
189 | self.assertNotIn(tempdir, result.output) | ||
190 | self.assertIn(self.workspacedir, result.output) | ||
191 | |||
192 | @OETestID(1159) | ||
193 | def test_devtool_add(self): | ||
194 | # Fetch source | ||
195 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
196 | self.track_for_cleanup(tempdir) | ||
197 | url = 'http://www.ivarch.com/programs/sources/pv-1.5.3.tar.bz2' | ||
198 | result = runCmd('wget %s' % url, cwd=tempdir) | ||
199 | result = runCmd('tar xfv pv-1.5.3.tar.bz2', cwd=tempdir) | ||
200 | srcdir = os.path.join(tempdir, 'pv-1.5.3') | ||
201 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory') | ||
202 | # Test devtool add | ||
203 | self.track_for_cleanup(self.workspacedir) | ||
204 | self.add_command_to_tearDown('bitbake -c cleansstate pv') | ||
205 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
206 | result = runCmd('devtool add pv %s' % srcdir) | ||
207 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') | ||
208 | # Test devtool status | ||
209 | result = runCmd('devtool status') | ||
210 | self.assertIn('pv', result.output) | ||
211 | self.assertIn(srcdir, result.output) | ||
212 | # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then) | ||
213 | bitbake('pv -c cleansstate') | ||
214 | # Test devtool build | ||
215 | result = runCmd('devtool build pv') | ||
216 | bb_vars = get_bb_vars(['D', 'bindir'], 'pv') | ||
217 | installdir = bb_vars['D'] | ||
218 | self.assertTrue(installdir, 'Could not query installdir variable') | ||
219 | bindir = bb_vars['bindir'] | ||
220 | self.assertTrue(bindir, 'Could not query bindir variable') | ||
221 | if bindir[0] == '/': | ||
222 | bindir = bindir[1:] | ||
223 | self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D') | ||
224 | |||
225 | @OETestID(1423) | ||
226 | def test_devtool_add_git_local(self): | ||
227 | # Fetch source from a remote URL, but do it outside of devtool | ||
228 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
229 | self.track_for_cleanup(tempdir) | ||
230 | pn = 'dbus-wait' | ||
231 | srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517' | ||
232 | # We choose an https:// git URL here to check rewriting the URL works | ||
233 | url = 'https://git.yoctoproject.org/git/dbus-wait' | ||
234 | # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf | ||
235 | # instead of the directory name | ||
236 | result = runCmd('git clone %s noname' % url, cwd=tempdir) | ||
237 | srcdir = os.path.join(tempdir, 'noname') | ||
238 | result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir) | ||
239 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory') | ||
240 | # Test devtool add | ||
241 | self.track_for_cleanup(self.workspacedir) | ||
242 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
243 | # Don't specify a name since we should be able to auto-detect it | ||
244 | result = runCmd('devtool add %s' % srcdir) | ||
245 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') | ||
246 | # Check the recipe name is correct | ||
247 | recipefile = get_bb_var('FILE', pn) | ||
248 | self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named') | ||
249 | self.assertIn(recipefile, result.output) | ||
250 | # Test devtool status | ||
251 | result = runCmd('devtool status') | ||
252 | self.assertIn(pn, result.output) | ||
253 | self.assertIn(srcdir, result.output) | ||
254 | self.assertIn(recipefile, result.output) | ||
255 | checkvars = {} | ||
256 | checkvars['LICENSE'] = 'GPLv2' | ||
257 | checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263' | ||
258 | checkvars['S'] = '${WORKDIR}/git' | ||
259 | checkvars['PV'] = '0.1+git${SRCPV}' | ||
260 | checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https' | ||
261 | checkvars['SRCREV'] = srcrev | ||
262 | checkvars['DEPENDS'] = set(['dbus']) | ||
263 | self._test_recipe_contents(recipefile, checkvars, []) | ||
264 | |||
265 | @OETestID(1162) | ||
266 | def test_devtool_add_library(self): | ||
267 | # Fetch source | ||
268 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
269 | self.track_for_cleanup(tempdir) | ||
270 | version = '1.1' | ||
271 | url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version | ||
272 | result = runCmd('wget %s' % url, cwd=tempdir) | ||
273 | result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir) | ||
274 | srcdir = os.path.join(tempdir, 'libftdi1-%s' % version) | ||
275 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory') | ||
276 | # Test devtool add (and use -V so we test that too) | ||
277 | self.track_for_cleanup(self.workspacedir) | ||
278 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
279 | result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version)) | ||
280 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') | ||
281 | # Test devtool status | ||
282 | result = runCmd('devtool status') | ||
283 | self.assertIn('libftdi', result.output) | ||
284 | self.assertIn(srcdir, result.output) | ||
285 | # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then) | ||
286 | bitbake('libftdi -c cleansstate') | ||
287 | # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it | ||
288 | # There's also the matter of it installing cmake files to a path we don't | ||
289 | # normally cover, which triggers the installed-vs-shipped QA test we have | ||
290 | # within do_package | ||
291 | recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version) | ||
292 | result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile) | ||
293 | with open(recipefile, 'a') as f: | ||
294 | f.write('\nFILES_${PN}-dev += "${datadir}/cmake/Modules"\n') | ||
295 | # We don't have the ability to pick up this dependency automatically yet... | ||
296 | f.write('\nDEPENDS += "libusb1"\n') | ||
297 | f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n') | ||
298 | # Test devtool build | ||
299 | result = runCmd('devtool build libftdi') | ||
300 | bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi') | ||
301 | staging_libdir = bb_vars['TESTLIBOUTPUT'] | ||
302 | self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable') | ||
303 | 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) | ||
304 | # Test devtool reset | ||
305 | stampprefix = bb_vars['STAMP'] | ||
306 | result = runCmd('devtool reset libftdi') | ||
307 | result = runCmd('devtool status') | ||
308 | self.assertNotIn('libftdi', result.output) | ||
309 | self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi') | ||
310 | matches = glob.glob(stampprefix + '*') | ||
311 | self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned') | ||
312 | self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning') | ||
313 | |||
314 | @OETestID(1160) | ||
315 | def test_devtool_add_fetch(self): | ||
316 | # Fetch source | ||
317 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
318 | self.track_for_cleanup(tempdir) | ||
319 | testver = '0.23' | ||
320 | url = 'https://pypi.python.org/packages/source/M/MarkupSafe/MarkupSafe-%s.tar.gz' % testver | ||
321 | testrecipe = 'python-markupsafe' | ||
322 | srcdir = os.path.join(tempdir, testrecipe) | ||
323 | # Test devtool add | ||
324 | self.track_for_cleanup(self.workspacedir) | ||
325 | self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe) | ||
326 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
327 | result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url)) | ||
328 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created. %s' % result.output) | ||
329 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory') | ||
330 | self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created') | ||
331 | # Test devtool status | ||
332 | result = runCmd('devtool status') | ||
333 | self.assertIn(testrecipe, result.output) | ||
334 | self.assertIn(srcdir, result.output) | ||
335 | # Check recipe | ||
336 | recipefile = get_bb_var('FILE', testrecipe) | ||
337 | self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named') | ||
338 | checkvars = {} | ||
339 | checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}' | ||
340 | checkvars['SRC_URI'] = url.replace(testver, '${PV}') | ||
341 | self._test_recipe_contents(recipefile, checkvars, []) | ||
342 | # Try with version specified | ||
343 | result = runCmd('devtool reset -n %s' % testrecipe) | ||
344 | shutil.rmtree(srcdir) | ||
345 | fakever = '1.9' | ||
346 | result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever)) | ||
347 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory') | ||
348 | # Test devtool status | ||
349 | result = runCmd('devtool status') | ||
350 | self.assertIn(testrecipe, result.output) | ||
351 | self.assertIn(srcdir, result.output) | ||
352 | # Check recipe | ||
353 | recipefile = get_bb_var('FILE', testrecipe) | ||
354 | self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named') | ||
355 | checkvars = {} | ||
356 | checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver | ||
357 | checkvars['SRC_URI'] = url | ||
358 | self._test_recipe_contents(recipefile, checkvars, []) | ||
359 | |||
360 | @OETestID(1161) | ||
361 | def test_devtool_add_fetch_git(self): | ||
362 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
363 | self.track_for_cleanup(tempdir) | ||
364 | url = 'gitsm://git.yoctoproject.org/mraa' | ||
365 | checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d' | ||
366 | testrecipe = 'mraa' | ||
367 | srcdir = os.path.join(tempdir, testrecipe) | ||
368 | # Test devtool add | ||
369 | self.track_for_cleanup(self.workspacedir) | ||
370 | self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe) | ||
371 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
372 | result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url)) | ||
373 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created: %s' % result.output) | ||
374 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory') | ||
375 | # Test devtool status | ||
376 | result = runCmd('devtool status') | ||
377 | self.assertIn(testrecipe, result.output) | ||
378 | self.assertIn(srcdir, result.output) | ||
379 | # Check recipe | ||
380 | recipefile = get_bb_var('FILE', testrecipe) | ||
381 | self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named') | ||
382 | checkvars = {} | ||
383 | checkvars['S'] = '${WORKDIR}/git' | ||
384 | checkvars['PV'] = '1.0+git${SRCPV}' | ||
385 | checkvars['SRC_URI'] = url | ||
386 | checkvars['SRCREV'] = '${AUTOREV}' | ||
387 | self._test_recipe_contents(recipefile, checkvars, []) | ||
388 | # Try with revision and version specified | ||
389 | result = runCmd('devtool reset -n %s' % testrecipe) | ||
390 | shutil.rmtree(srcdir) | ||
391 | url_rev = '%s;rev=%s' % (url, checkrev) | ||
392 | result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev)) | ||
393 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory') | ||
394 | # Test devtool status | ||
395 | result = runCmd('devtool status') | ||
396 | self.assertIn(testrecipe, result.output) | ||
397 | self.assertIn(srcdir, result.output) | ||
398 | # Check recipe | ||
399 | recipefile = get_bb_var('FILE', testrecipe) | ||
400 | self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named') | ||
401 | checkvars = {} | ||
402 | checkvars['S'] = '${WORKDIR}/git' | ||
403 | checkvars['PV'] = '1.5+git${SRCPV}' | ||
404 | checkvars['SRC_URI'] = url | ||
405 | checkvars['SRCREV'] = checkrev | ||
406 | self._test_recipe_contents(recipefile, checkvars, []) | ||
407 | |||
408 | @OETestID(1391) | ||
409 | def test_devtool_add_fetch_simple(self): | ||
410 | # Fetch source from a remote URL, auto-detecting name | ||
411 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
412 | self.track_for_cleanup(tempdir) | ||
413 | testver = '1.6.0' | ||
414 | url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver | ||
415 | testrecipe = 'pv' | ||
416 | srcdir = os.path.join(self.workspacedir, 'sources', testrecipe) | ||
417 | # Test devtool add | ||
418 | self.track_for_cleanup(self.workspacedir) | ||
419 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
420 | result = runCmd('devtool add %s' % url) | ||
421 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created. %s' % result.output) | ||
422 | self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory') | ||
423 | self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created') | ||
424 | # Test devtool status | ||
425 | result = runCmd('devtool status') | ||
426 | self.assertIn(testrecipe, result.output) | ||
427 | self.assertIn(srcdir, result.output) | ||
428 | # Check recipe | ||
429 | recipefile = get_bb_var('FILE', testrecipe) | ||
430 | self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named') | ||
431 | checkvars = {} | ||
432 | checkvars['S'] = None | ||
433 | checkvars['SRC_URI'] = url.replace(testver, '${PV}') | ||
434 | self._test_recipe_contents(recipefile, checkvars, []) | ||
435 | |||
436 | @OETestID(1164) | ||
437 | def test_devtool_modify(self): | ||
438 | import oe.path | ||
439 | |||
440 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
441 | self.track_for_cleanup(tempdir) | ||
442 | self.track_for_cleanup(self.workspacedir) | ||
443 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
444 | self.add_command_to_tearDown('bitbake -c clean mdadm') | ||
445 | result = runCmd('devtool modify mdadm -x %s' % tempdir) | ||
446 | self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile')), 'Extracted source could not be found') | ||
447 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') | ||
448 | matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend')) | ||
449 | self.assertTrue(matches, 'bbappend not created %s' % result.output) | ||
450 | |||
451 | # Test devtool status | ||
452 | result = runCmd('devtool status') | ||
453 | self.assertIn('mdadm', result.output) | ||
454 | self.assertIn(tempdir, result.output) | ||
455 | self._check_src_repo(tempdir) | ||
456 | |||
457 | bitbake('mdadm -C unpack') | ||
458 | |||
459 | def check_line(checkfile, expected, message, present=True): | ||
460 | # Check for $expected, on a line on its own, in checkfile. | ||
461 | with open(checkfile, 'r') as f: | ||
462 | if present: | ||
463 | self.assertIn(expected + '\n', f, message) | ||
464 | else: | ||
465 | self.assertNotIn(expected + '\n', f, message) | ||
466 | |||
467 | modfile = os.path.join(tempdir, 'mdadm.8.in') | ||
468 | bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm') | ||
469 | pkgd = bb_vars['PKGD'] | ||
470 | self.assertTrue(pkgd, 'Could not query PKGD variable') | ||
471 | mandir = bb_vars['mandir'] | ||
472 | self.assertTrue(mandir, 'Could not query mandir variable') | ||
473 | manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8') | ||
474 | |||
475 | check_line(modfile, 'Linux Software RAID', 'Could not find initial string') | ||
476 | check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False) | ||
477 | |||
478 | result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile) | ||
479 | check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)') | ||
480 | |||
481 | bitbake('mdadm -c package') | ||
482 | check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile) | ||
483 | |||
484 | result = runCmd('git checkout -- %s' % modfile, cwd=tempdir) | ||
485 | check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)') | ||
486 | |||
487 | bitbake('mdadm -c package') | ||
488 | check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile) | ||
489 | |||
490 | result = runCmd('devtool reset mdadm') | ||
491 | result = runCmd('devtool status') | ||
492 | self.assertNotIn('mdadm', result.output) | ||
493 | |||
494 | def test_devtool_buildclean(self): | ||
495 | def assertFile(path, *paths): | ||
496 | f = os.path.join(path, *paths) | ||
497 | self.assertTrue(os.path.exists(f), "%r does not exist" % f) | ||
498 | def assertNoFile(path, *paths): | ||
499 | f = os.path.join(path, *paths) | ||
500 | self.assertFalse(os.path.exists(os.path.join(f)), "%r exists" % f) | ||
501 | |||
502 | # Clean up anything in the workdir/sysroot/sstate cache | ||
503 | bitbake('mdadm m4 -c cleansstate') | ||
504 | # Try modifying a recipe | ||
505 | tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa') | ||
506 | tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa') | ||
507 | builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa') | ||
508 | self.track_for_cleanup(tempdir_mdadm) | ||
509 | self.track_for_cleanup(tempdir_m4) | ||
510 | self.track_for_cleanup(builddir_m4) | ||
511 | self.track_for_cleanup(self.workspacedir) | ||
512 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
513 | self.add_command_to_tearDown('bitbake -c clean mdadm m4') | ||
514 | self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4) | ||
515 | try: | ||
516 | runCmd('devtool modify mdadm -x %s' % tempdir_mdadm) | ||
517 | runCmd('devtool modify m4 -x %s' % tempdir_m4) | ||
518 | assertNoFile(tempdir_mdadm, 'mdadm') | ||
519 | assertNoFile(builddir_m4, 'src/m4') | ||
520 | result = bitbake('m4 -e') | ||
521 | result = bitbake('mdadm m4 -c compile') | ||
522 | self.assertEqual(result.status, 0) | ||
523 | assertFile(tempdir_mdadm, 'mdadm') | ||
524 | assertFile(builddir_m4, 'src/m4') | ||
525 | # Check that buildclean task exists and does call make clean | ||
526 | bitbake('mdadm m4 -c buildclean') | ||
527 | assertNoFile(tempdir_mdadm, 'mdadm') | ||
528 | assertNoFile(builddir_m4, 'src/m4') | ||
529 | bitbake('mdadm m4 -c compile') | ||
530 | assertFile(tempdir_mdadm, 'mdadm') | ||
531 | assertFile(builddir_m4, 'src/m4') | ||
532 | bitbake('mdadm m4 -c clean') | ||
533 | # Check that buildclean task is run before clean for B == S | ||
534 | assertNoFile(tempdir_mdadm, 'mdadm') | ||
535 | # Check that buildclean task is not run before clean for B != S | ||
536 | assertFile(builddir_m4, 'src/m4') | ||
537 | finally: | ||
538 | self.delete_recipeinc('m4') | ||
539 | |||
540 | @OETestID(1166) | ||
541 | def test_devtool_modify_invalid(self): | ||
542 | # Try modifying some recipes | ||
543 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
544 | self.track_for_cleanup(tempdir) | ||
545 | self.track_for_cleanup(self.workspacedir) | ||
546 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
547 | |||
548 | testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk meta-ide-support'.split() | ||
549 | # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose | ||
550 | result = runCmd('bitbake-layers show-recipes gcc-source*') | ||
551 | for line in result.output.splitlines(): | ||
552 | # just match those lines that contain a real target | ||
553 | m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line) | ||
554 | if m: | ||
555 | testrecipes.append(m.group('recipe')) | ||
556 | for testrecipe in testrecipes: | ||
557 | # Check it's a valid recipe | ||
558 | bitbake('%s -e' % testrecipe) | ||
559 | # devtool extract should fail | ||
560 | result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True) | ||
561 | self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output)) | ||
562 | self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe) | ||
563 | self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe) | ||
564 | # devtool modify should fail | ||
565 | result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True) | ||
566 | self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output)) | ||
567 | self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe) | ||
568 | |||
569 | @OETestID(1365) | ||
570 | def test_devtool_modify_native(self): | ||
571 | # Check preconditions | ||
572 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
573 | # Try modifying some recipes | ||
574 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
575 | self.track_for_cleanup(tempdir) | ||
576 | self.track_for_cleanup(self.workspacedir) | ||
577 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
578 | |||
579 | bbclassextended = False | ||
580 | inheritnative = False | ||
581 | testrecipes = 'mtools-native apt-native desktop-file-utils-native'.split() | ||
582 | for testrecipe in testrecipes: | ||
583 | checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split() | ||
584 | if not bbclassextended: | ||
585 | bbclassextended = checkextend | ||
586 | if not inheritnative: | ||
587 | inheritnative = not checkextend | ||
588 | result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe))) | ||
589 | self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output) | ||
590 | result = runCmd('devtool build %s' % testrecipe) | ||
591 | self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output) | ||
592 | result = runCmd('devtool reset %s' % testrecipe) | ||
593 | self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output) | ||
594 | |||
595 | self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes)) | ||
596 | self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes)) | ||
597 | |||
598 | |||
599 | @OETestID(1165) | ||
600 | def test_devtool_modify_git(self): | ||
601 | # Check preconditions | ||
602 | testrecipe = 'mkelfimage' | ||
603 | src_uri = get_bb_var('SRC_URI', testrecipe) | ||
604 | self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe) | ||
605 | # Clean up anything in the workdir/sysroot/sstate cache | ||
606 | bitbake('%s -c cleansstate' % testrecipe) | ||
607 | # Try modifying a recipe | ||
608 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
609 | self.track_for_cleanup(tempdir) | ||
610 | self.track_for_cleanup(self.workspacedir) | ||
611 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
612 | self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) | ||
613 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) | ||
614 | self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile')), 'Extracted source could not be found') | ||
615 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created. devtool output: %s' % result.output) | ||
616 | matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mkelfimage_*.bbappend')) | ||
617 | self.assertTrue(matches, 'bbappend not created') | ||
618 | # Test devtool status | ||
619 | result = runCmd('devtool status') | ||
620 | self.assertIn(testrecipe, result.output) | ||
621 | self.assertIn(tempdir, result.output) | ||
622 | # Check git repo | ||
623 | self._check_src_repo(tempdir) | ||
624 | # Try building | ||
625 | bitbake(testrecipe) | ||
626 | |||
627 | @OETestID(1167) | ||
628 | def test_devtool_modify_localfiles(self): | ||
629 | # Check preconditions | ||
630 | testrecipe = 'lighttpd' | ||
631 | src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split() | ||
632 | foundlocal = False | ||
633 | for item in src_uri: | ||
634 | if item.startswith('file://') and '.patch' not in item: | ||
635 | foundlocal = True | ||
636 | break | ||
637 | self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe) | ||
638 | # Clean up anything in the workdir/sysroot/sstate cache | ||
639 | bitbake('%s -c cleansstate' % testrecipe) | ||
640 | # Try modifying a recipe | ||
641 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
642 | self.track_for_cleanup(tempdir) | ||
643 | self.track_for_cleanup(self.workspacedir) | ||
644 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
645 | self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) | ||
646 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) | ||
647 | self.assertTrue(os.path.exists(os.path.join(tempdir, 'configure.ac')), 'Extracted source could not be found') | ||
648 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') | ||
649 | matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe)) | ||
650 | self.assertTrue(matches, 'bbappend not created') | ||
651 | # Test devtool status | ||
652 | result = runCmd('devtool status') | ||
653 | self.assertIn(testrecipe, result.output) | ||
654 | self.assertIn(tempdir, result.output) | ||
655 | # Try building | ||
656 | bitbake(testrecipe) | ||
657 | |||
658 | @OETestID(1378) | ||
659 | def test_devtool_modify_virtual(self): | ||
660 | # Try modifying a virtual recipe | ||
661 | virtrecipe = 'virtual/make' | ||
662 | realrecipe = 'make' | ||
663 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
664 | self.track_for_cleanup(tempdir) | ||
665 | self.track_for_cleanup(self.workspacedir) | ||
666 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
667 | result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir)) | ||
668 | self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile.am')), 'Extracted source could not be found') | ||
669 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created') | ||
670 | matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe)) | ||
671 | self.assertTrue(matches, 'bbappend not created %s' % result.output) | ||
672 | # Test devtool status | ||
673 | result = runCmd('devtool status') | ||
674 | self.assertNotIn(virtrecipe, result.output) | ||
675 | self.assertIn(realrecipe, result.output) | ||
676 | # Check git repo | ||
677 | self._check_src_repo(tempdir) | ||
678 | # This is probably sufficient | ||
679 | |||
680 | |||
681 | @OETestID(1169) | ||
682 | def test_devtool_update_recipe(self): | ||
683 | # Check preconditions | ||
684 | testrecipe = 'minicom' | ||
685 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) | ||
686 | recipefile = bb_vars['FILE'] | ||
687 | src_uri = bb_vars['SRC_URI'] | ||
688 | self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe) | ||
689 | self._check_repo_status(os.path.dirname(recipefile), []) | ||
690 | # First, modify a recipe | ||
691 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
692 | self.track_for_cleanup(tempdir) | ||
693 | self.track_for_cleanup(self.workspacedir) | ||
694 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
695 | # (don't bother with cleaning the recipe on teardown, we won't be building it) | ||
696 | # We don't use -x here so that we test the behaviour of devtool modify without it | ||
697 | result = runCmd('devtool modify %s %s' % (testrecipe, tempdir)) | ||
698 | # Check git repo | ||
699 | self._check_src_repo(tempdir) | ||
700 | # Add a couple of commits | ||
701 | # FIXME: this only tests adding, need to also test update and remove | ||
702 | result = runCmd('echo "Additional line" >> README', cwd=tempdir) | ||
703 | result = runCmd('git commit -a -m "Change the README"', cwd=tempdir) | ||
704 | result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir) | ||
705 | result = runCmd('git add devtool-new-file', cwd=tempdir) | ||
706 | result = runCmd('git commit -m "Add a new file"', cwd=tempdir) | ||
707 | self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) | ||
708 | result = runCmd('devtool update-recipe %s' % testrecipe) | ||
709 | expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), | ||
710 | ('??', '.*/0001-Change-the-README.patch$'), | ||
711 | ('??', '.*/0002-Add-a-new-file.patch$')] | ||
712 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | ||
713 | |||
714 | @OETestID(1172) | ||
715 | def test_devtool_update_recipe_git(self): | ||
716 | # Check preconditions | ||
717 | testrecipe = 'mtd-utils' | ||
718 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) | ||
719 | recipefile = bb_vars['FILE'] | ||
720 | src_uri = bb_vars['SRC_URI'] | ||
721 | self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe) | ||
722 | patches = [] | ||
723 | for entry in src_uri.split(): | ||
724 | if entry.startswith('file://') and entry.endswith('.patch'): | ||
725 | patches.append(entry[7:].split(';')[0]) | ||
726 | self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe) | ||
727 | self._check_repo_status(os.path.dirname(recipefile), []) | ||
728 | # First, modify a recipe | ||
729 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
730 | self.track_for_cleanup(tempdir) | ||
731 | self.track_for_cleanup(self.workspacedir) | ||
732 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
733 | # (don't bother with cleaning the recipe on teardown, we won't be building it) | ||
734 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) | ||
735 | # Check git repo | ||
736 | self._check_src_repo(tempdir) | ||
737 | # Add a couple of commits | ||
738 | # FIXME: this only tests adding, need to also test update and remove | ||
739 | result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir) | ||
740 | result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir) | ||
741 | result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir) | ||
742 | result = runCmd('git add devtool-new-file', cwd=tempdir) | ||
743 | result = runCmd('git commit -m "Add a new file"', cwd=tempdir) | ||
744 | self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) | ||
745 | result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe) | ||
746 | expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \ | ||
747 | [(' D', '.*/%s$' % patch) for patch in patches] | ||
748 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | ||
749 | |||
750 | result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile)) | ||
751 | addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git"'] | ||
752 | srcurilines = src_uri.split() | ||
753 | srcurilines[0] = 'SRC_URI = "' + srcurilines[0] | ||
754 | srcurilines.append('"') | ||
755 | removelines = ['SRCREV = ".*"'] + srcurilines | ||
756 | for line in result.output.splitlines(): | ||
757 | if line.startswith('+++') or line.startswith('---'): | ||
758 | continue | ||
759 | elif line.startswith('+'): | ||
760 | matched = False | ||
761 | for item in addlines: | ||
762 | if re.match(item, line[1:].strip()): | ||
763 | matched = True | ||
764 | break | ||
765 | self.assertTrue(matched, 'Unexpected diff add line: %s' % line) | ||
766 | elif line.startswith('-'): | ||
767 | matched = False | ||
768 | for item in removelines: | ||
769 | if re.match(item, line[1:].strip()): | ||
770 | matched = True | ||
771 | break | ||
772 | self.assertTrue(matched, 'Unexpected diff remove line: %s' % line) | ||
773 | # Now try with auto mode | ||
774 | runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile))) | ||
775 | result = runCmd('devtool update-recipe %s' % testrecipe) | ||
776 | result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile)) | ||
777 | topleveldir = result.output.strip() | ||
778 | relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe) | ||
779 | expected_status = [(' M', os.path.relpath(recipefile, topleveldir)), | ||
780 | ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath), | ||
781 | ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)] | ||
782 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | ||
783 | |||
784 | @OETestID(1170) | ||
785 | def test_devtool_update_recipe_append(self): | ||
786 | # Check preconditions | ||
787 | testrecipe = 'mdadm' | ||
788 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) | ||
789 | recipefile = bb_vars['FILE'] | ||
790 | src_uri = bb_vars['SRC_URI'] | ||
791 | self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe) | ||
792 | self._check_repo_status(os.path.dirname(recipefile), []) | ||
793 | # First, modify a recipe | ||
794 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
795 | tempsrcdir = os.path.join(tempdir, 'source') | ||
796 | templayerdir = os.path.join(tempdir, 'layer') | ||
797 | self.track_for_cleanup(tempdir) | ||
798 | self.track_for_cleanup(self.workspacedir) | ||
799 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
800 | # (don't bother with cleaning the recipe on teardown, we won't be building it) | ||
801 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir)) | ||
802 | # Check git repo | ||
803 | self._check_src_repo(tempsrcdir) | ||
804 | # Add a commit | ||
805 | result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir) | ||
806 | result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir) | ||
807 | self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe)) | ||
808 | # Create a temporary layer and add it to bblayers.conf | ||
809 | self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe') | ||
810 | # Create the bbappend | ||
811 | result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) | ||
812 | self.assertNotIn('WARNING:', result.output) | ||
813 | # Check recipe is still clean | ||
814 | self._check_repo_status(os.path.dirname(recipefile), []) | ||
815 | # Check bbappend was created | ||
816 | splitpath = os.path.dirname(recipefile).split(os.sep) | ||
817 | appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1]) | ||
818 | bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir) | ||
819 | patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch') | ||
820 | self.assertTrue(os.path.exists(patchfile), 'Patch file not created') | ||
821 | |||
822 | # Check bbappend contents | ||
823 | expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', | ||
824 | '\n', | ||
825 | 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n', | ||
826 | '\n'] | ||
827 | with open(bbappendfile, 'r') as f: | ||
828 | self.assertEqual(expectedlines, f.readlines()) | ||
829 | |||
830 | # Check we can run it again and bbappend isn't modified | ||
831 | result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) | ||
832 | with open(bbappendfile, 'r') as f: | ||
833 | self.assertEqual(expectedlines, f.readlines()) | ||
834 | # Drop new commit and check patch gets deleted | ||
835 | result = runCmd('git reset HEAD^', cwd=tempsrcdir) | ||
836 | result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) | ||
837 | self.assertFalse(os.path.exists(patchfile), 'Patch file not deleted') | ||
838 | expectedlines2 = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n', | ||
839 | '\n'] | ||
840 | with open(bbappendfile, 'r') as f: | ||
841 | self.assertEqual(expectedlines2, f.readlines()) | ||
842 | # Put commit back and check we can run it if layer isn't in bblayers.conf | ||
843 | os.remove(bbappendfile) | ||
844 | result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir) | ||
845 | result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir) | ||
846 | result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir)) | ||
847 | self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output) | ||
848 | self.assertTrue(os.path.exists(patchfile), 'Patch file not created (with disabled layer)') | ||
849 | with open(bbappendfile, 'r') as f: | ||
850 | self.assertEqual(expectedlines, f.readlines()) | ||
851 | # Deleting isn't expected to work under these circumstances | ||
852 | |||
853 | @OETestID(1171) | ||
854 | def test_devtool_update_recipe_append_git(self): | ||
855 | # Check preconditions | ||
856 | testrecipe = 'mtd-utils' | ||
857 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) | ||
858 | recipefile = bb_vars['FILE'] | ||
859 | src_uri = bb_vars['SRC_URI'] | ||
860 | self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe) | ||
861 | for entry in src_uri.split(): | ||
862 | if entry.startswith('git://'): | ||
863 | git_uri = entry | ||
864 | break | ||
865 | self._check_repo_status(os.path.dirname(recipefile), []) | ||
866 | # First, modify a recipe | ||
867 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
868 | tempsrcdir = os.path.join(tempdir, 'source') | ||
869 | templayerdir = os.path.join(tempdir, 'layer') | ||
870 | self.track_for_cleanup(tempdir) | ||
871 | self.track_for_cleanup(self.workspacedir) | ||
872 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
873 | # (don't bother with cleaning the recipe on teardown, we won't be building it) | ||
874 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir)) | ||
875 | # Check git repo | ||
876 | self._check_src_repo(tempsrcdir) | ||
877 | # Add a commit | ||
878 | result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir) | ||
879 | result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir) | ||
880 | self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe)) | ||
881 | # Create a temporary layer | ||
882 | os.makedirs(os.path.join(templayerdir, 'conf')) | ||
883 | with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f: | ||
884 | f.write('BBPATH .= ":${LAYERDIR}"\n') | ||
885 | f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n') | ||
886 | f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n') | ||
887 | f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n') | ||
888 | f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n') | ||
889 | f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n') | ||
890 | self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir) | ||
891 | result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir) | ||
892 | # Create the bbappend | ||
893 | result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir)) | ||
894 | self.assertNotIn('WARNING:', result.output) | ||
895 | # Check recipe is still clean | ||
896 | self._check_repo_status(os.path.dirname(recipefile), []) | ||
897 | # Check bbappend was created | ||
898 | splitpath = os.path.dirname(recipefile).split(os.sep) | ||
899 | appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1]) | ||
900 | bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir) | ||
901 | self.assertFalse(os.path.exists(os.path.join(appenddir, testrecipe)), 'Patch directory should not be created') | ||
902 | |||
903 | # Check bbappend contents | ||
904 | result = runCmd('git rev-parse HEAD', cwd=tempsrcdir) | ||
905 | expectedlines = set(['SRCREV = "%s"\n' % result.output, | ||
906 | '\n', | ||
907 | 'SRC_URI = "%s"\n' % git_uri, | ||
908 | '\n']) | ||
909 | with open(bbappendfile, 'r') as f: | ||
910 | self.assertEqual(expectedlines, set(f.readlines())) | ||
911 | |||
912 | # Check we can run it again and bbappend isn't modified | ||
913 | result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir)) | ||
914 | with open(bbappendfile, 'r') as f: | ||
915 | self.assertEqual(expectedlines, set(f.readlines())) | ||
916 | # Drop new commit and check SRCREV changes | ||
917 | result = runCmd('git reset HEAD^', cwd=tempsrcdir) | ||
918 | result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir)) | ||
919 | self.assertFalse(os.path.exists(os.path.join(appenddir, testrecipe)), 'Patch directory should not be created') | ||
920 | result = runCmd('git rev-parse HEAD', cwd=tempsrcdir) | ||
921 | expectedlines = set(['SRCREV = "%s"\n' % result.output, | ||
922 | '\n', | ||
923 | 'SRC_URI = "%s"\n' % git_uri, | ||
924 | '\n']) | ||
925 | with open(bbappendfile, 'r') as f: | ||
926 | self.assertEqual(expectedlines, set(f.readlines())) | ||
927 | # Put commit back and check we can run it if layer isn't in bblayers.conf | ||
928 | os.remove(bbappendfile) | ||
929 | result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir) | ||
930 | result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir) | ||
931 | result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir)) | ||
932 | self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output) | ||
933 | self.assertFalse(os.path.exists(os.path.join(appenddir, testrecipe)), 'Patch directory should not be created') | ||
934 | result = runCmd('git rev-parse HEAD', cwd=tempsrcdir) | ||
935 | expectedlines = set(['SRCREV = "%s"\n' % result.output, | ||
936 | '\n', | ||
937 | 'SRC_URI = "%s"\n' % git_uri, | ||
938 | '\n']) | ||
939 | with open(bbappendfile, 'r') as f: | ||
940 | self.assertEqual(expectedlines, set(f.readlines())) | ||
941 | # Deleting isn't expected to work under these circumstances | ||
942 | |||
943 | @OETestID(1370) | ||
944 | def test_devtool_update_recipe_local_files(self): | ||
945 | """Check that local source files are copied over instead of patched""" | ||
946 | testrecipe = 'makedevs' | ||
947 | recipefile = get_bb_var('FILE', testrecipe) | ||
948 | # Setup srctree for modifying the recipe | ||
949 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
950 | self.track_for_cleanup(tempdir) | ||
951 | self.track_for_cleanup(self.workspacedir) | ||
952 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
953 | # (don't bother with cleaning the recipe on teardown, we won't be | ||
954 | # building it) | ||
955 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) | ||
956 | # Check git repo | ||
957 | self._check_src_repo(tempdir) | ||
958 | # Try building just to ensure we haven't broken that | ||
959 | bitbake("%s" % testrecipe) | ||
960 | # Edit / commit local source | ||
961 | runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir) | ||
962 | runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir) | ||
963 | runCmd('echo "Bar" > new-file', cwd=tempdir) | ||
964 | runCmd('git add new-file', cwd=tempdir) | ||
965 | runCmd('git commit -m "Add new file"', cwd=tempdir) | ||
966 | self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' % | ||
967 | os.path.dirname(recipefile)) | ||
968 | runCmd('devtool update-recipe %s' % testrecipe) | ||
969 | expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), | ||
970 | (' M', '.*/makedevs/makedevs.c$'), | ||
971 | ('??', '.*/makedevs/new-local$'), | ||
972 | ('??', '.*/makedevs/0001-Add-new-file.patch$')] | ||
973 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | ||
974 | |||
975 | @OETestID(1371) | ||
976 | def test_devtool_update_recipe_local_files_2(self): | ||
977 | """Check local source files support when oe-local-files is in Git""" | ||
978 | testrecipe = 'lzo' | ||
979 | recipefile = get_bb_var('FILE', testrecipe) | ||
980 | # Setup srctree for modifying the recipe | ||
981 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
982 | self.track_for_cleanup(tempdir) | ||
983 | self.track_for_cleanup(self.workspacedir) | ||
984 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
985 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) | ||
986 | # Check git repo | ||
987 | self._check_src_repo(tempdir) | ||
988 | # Add oe-local-files to Git | ||
989 | runCmd('rm oe-local-files/.gitignore', cwd=tempdir) | ||
990 | runCmd('git add oe-local-files', cwd=tempdir) | ||
991 | runCmd('git commit -m "Add local sources"', cwd=tempdir) | ||
992 | # Edit / commit local sources | ||
993 | runCmd('echo "# Foobar" >> oe-local-files/acinclude.m4', cwd=tempdir) | ||
994 | runCmd('git commit -am "Edit existing file"', cwd=tempdir) | ||
995 | runCmd('git rm oe-local-files/run-ptest', cwd=tempdir) | ||
996 | runCmd('git commit -m"Remove file"', cwd=tempdir) | ||
997 | runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir) | ||
998 | runCmd('git add oe-local-files/new-local', cwd=tempdir) | ||
999 | runCmd('git commit -m "Add new local file"', cwd=tempdir) | ||
1000 | runCmd('echo "Gar" > new-file', cwd=tempdir) | ||
1001 | runCmd('git add new-file', cwd=tempdir) | ||
1002 | runCmd('git commit -m "Add new file"', cwd=tempdir) | ||
1003 | self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' % | ||
1004 | os.path.dirname(recipefile)) | ||
1005 | # Checkout unmodified file to working copy -> devtool should still pick | ||
1006 | # the modified version from HEAD | ||
1007 | runCmd('git checkout HEAD^ -- oe-local-files/acinclude.m4', cwd=tempdir) | ||
1008 | runCmd('devtool update-recipe %s' % testrecipe) | ||
1009 | expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), | ||
1010 | (' M', '.*/acinclude.m4$'), | ||
1011 | (' D', '.*/run-ptest$'), | ||
1012 | ('??', '.*/new-local$'), | ||
1013 | ('??', '.*/0001-Add-new-file.patch$')] | ||
1014 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | ||
1015 | |||
1016 | def test_devtool_update_recipe_local_files_3(self): | ||
1017 | # First, modify the recipe | ||
1018 | testrecipe = 'devtool-test-localonly' | ||
1019 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) | ||
1020 | recipefile = bb_vars['FILE'] | ||
1021 | src_uri = bb_vars['SRC_URI'] | ||
1022 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1023 | self.track_for_cleanup(tempdir) | ||
1024 | self.track_for_cleanup(self.workspacedir) | ||
1025 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1026 | # (don't bother with cleaning the recipe on teardown, we won't be building it) | ||
1027 | result = runCmd('devtool modify %s' % testrecipe) | ||
1028 | # Modify one file | ||
1029 | runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files')) | ||
1030 | self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) | ||
1031 | result = runCmd('devtool update-recipe %s' % testrecipe) | ||
1032 | expected_status = [(' M', '.*/%s/file2$' % testrecipe)] | ||
1033 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | ||
1034 | |||
1035 | def test_devtool_update_recipe_local_patch_gz(self): | ||
1036 | # First, modify the recipe | ||
1037 | testrecipe = 'devtool-test-patch-gz' | ||
1038 | if get_bb_var('DISTRO') == 'poky-tiny': | ||
1039 | self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe) | ||
1040 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) | ||
1041 | recipefile = bb_vars['FILE'] | ||
1042 | src_uri = bb_vars['SRC_URI'] | ||
1043 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1044 | self.track_for_cleanup(tempdir) | ||
1045 | self.track_for_cleanup(self.workspacedir) | ||
1046 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1047 | # (don't bother with cleaning the recipe on teardown, we won't be building it) | ||
1048 | result = runCmd('devtool modify %s' % testrecipe) | ||
1049 | # Modify one file | ||
1050 | srctree = os.path.join(self.workspacedir, 'sources', testrecipe) | ||
1051 | runCmd('echo "Another line" >> README', cwd=srctree) | ||
1052 | runCmd('git commit -a --amend --no-edit', cwd=srctree) | ||
1053 | self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) | ||
1054 | result = runCmd('devtool update-recipe %s' % testrecipe) | ||
1055 | expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)] | ||
1056 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | ||
1057 | patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz') | ||
1058 | result = runCmd('file %s' % patch_gz) | ||
1059 | if 'gzip compressed data' not in result.output: | ||
1060 | self.fail('New patch file is not gzipped - file reports:\n%s' % result.output) | ||
1061 | |||
1062 | def test_devtool_update_recipe_local_files_subdir(self): | ||
1063 | # Try devtool extract on a recipe that has a file with subdir= set in | ||
1064 | # SRC_URI such that it overwrites a file that was in an archive that | ||
1065 | # was also in SRC_URI | ||
1066 | # First, modify the recipe | ||
1067 | testrecipe = 'devtool-test-subdir' | ||
1068 | bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe) | ||
1069 | recipefile = bb_vars['FILE'] | ||
1070 | src_uri = bb_vars['SRC_URI'] | ||
1071 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1072 | self.track_for_cleanup(tempdir) | ||
1073 | self.track_for_cleanup(self.workspacedir) | ||
1074 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1075 | # (don't bother with cleaning the recipe on teardown, we won't be building it) | ||
1076 | result = runCmd('devtool modify %s' % testrecipe) | ||
1077 | testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile') | ||
1078 | self.assertTrue(os.path.exists(testfile), 'Extracted source could not be found') | ||
1079 | with open(testfile, 'r') as f: | ||
1080 | contents = f.read().rstrip() | ||
1081 | self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been') | ||
1082 | # Test devtool update-recipe without modifying any files | ||
1083 | self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))) | ||
1084 | result = runCmd('devtool update-recipe %s' % testrecipe) | ||
1085 | expected_status = [] | ||
1086 | self._check_repo_status(os.path.dirname(recipefile), expected_status) | ||
1087 | |||
1088 | @OETestID(1163) | ||
1089 | def test_devtool_extract(self): | ||
1090 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1091 | # Try devtool extract | ||
1092 | self.track_for_cleanup(tempdir) | ||
1093 | self.append_config('PREFERRED_PROVIDER_virtual/make = "remake"') | ||
1094 | result = runCmd('devtool extract remake %s' % tempdir) | ||
1095 | self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile.am')), 'Extracted source could not be found') | ||
1096 | # devtool extract shouldn't create the workspace | ||
1097 | self.assertFalse(os.path.exists(self.workspacedir)) | ||
1098 | self._check_src_repo(tempdir) | ||
1099 | |||
1100 | @OETestID(1379) | ||
1101 | def test_devtool_extract_virtual(self): | ||
1102 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1103 | # Try devtool extract | ||
1104 | self.track_for_cleanup(tempdir) | ||
1105 | result = runCmd('devtool extract virtual/make %s' % tempdir) | ||
1106 | self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile.am')), 'Extracted source could not be found') | ||
1107 | # devtool extract shouldn't create the workspace | ||
1108 | self.assertFalse(os.path.exists(self.workspacedir)) | ||
1109 | self._check_src_repo(tempdir) | ||
1110 | |||
1111 | @OETestID(1168) | ||
1112 | def test_devtool_reset_all(self): | ||
1113 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1114 | self.track_for_cleanup(tempdir) | ||
1115 | self.track_for_cleanup(self.workspacedir) | ||
1116 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1117 | testrecipe1 = 'mdadm' | ||
1118 | testrecipe2 = 'cronie' | ||
1119 | result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1))) | ||
1120 | result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2))) | ||
1121 | result = runCmd('devtool build %s' % testrecipe1) | ||
1122 | result = runCmd('devtool build %s' % testrecipe2) | ||
1123 | stampprefix1 = get_bb_var('STAMP', testrecipe1) | ||
1124 | self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1) | ||
1125 | stampprefix2 = get_bb_var('STAMP', testrecipe2) | ||
1126 | self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2) | ||
1127 | result = runCmd('devtool reset -a') | ||
1128 | self.assertIn(testrecipe1, result.output) | ||
1129 | self.assertIn(testrecipe2, result.output) | ||
1130 | result = runCmd('devtool status') | ||
1131 | self.assertNotIn(testrecipe1, result.output) | ||
1132 | self.assertNotIn(testrecipe2, result.output) | ||
1133 | matches1 = glob.glob(stampprefix1 + '*') | ||
1134 | self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1) | ||
1135 | matches2 = glob.glob(stampprefix2 + '*') | ||
1136 | self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2) | ||
1137 | |||
1138 | @OETestID(1272) | ||
1139 | def test_devtool_deploy_target(self): | ||
1140 | # NOTE: Whilst this test would seemingly be better placed as a runtime test, | ||
1141 | # unfortunately the runtime tests run under bitbake and you can't run | ||
1142 | # devtool within bitbake (since devtool needs to run bitbake itself). | ||
1143 | # Additionally we are testing build-time functionality as well, so | ||
1144 | # really this has to be done as an oe-selftest test. | ||
1145 | # | ||
1146 | # Check preconditions | ||
1147 | machine = get_bb_var('MACHINE') | ||
1148 | if not machine.startswith('qemu'): | ||
1149 | self.skipTest('This test only works with qemu machines') | ||
1150 | if not os.path.exists('/etc/runqemu-nosudo'): | ||
1151 | self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test') | ||
1152 | result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True) | ||
1153 | if result.status != 0: | ||
1154 | result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True) | ||
1155 | if result.status != 0: | ||
1156 | self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output) | ||
1157 | for line in result.output.splitlines(): | ||
1158 | if line.startswith('tap'): | ||
1159 | break | ||
1160 | else: | ||
1161 | self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test') | ||
1162 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
1163 | # Definitions | ||
1164 | testrecipe = 'mdadm' | ||
1165 | testfile = '/sbin/mdadm' | ||
1166 | testimage = 'oe-selftest-image' | ||
1167 | testcommand = '/sbin/mdadm --help' | ||
1168 | # Build an image to run | ||
1169 | bitbake("%s qemu-native qemu-helper-native" % testimage) | ||
1170 | deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') | ||
1171 | self.add_command_to_tearDown('bitbake -c clean %s' % testimage) | ||
1172 | self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage)) | ||
1173 | # Clean recipe so the first deploy will fail | ||
1174 | bitbake("%s -c clean" % testrecipe) | ||
1175 | # Try devtool modify | ||
1176 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1177 | self.track_for_cleanup(tempdir) | ||
1178 | self.track_for_cleanup(self.workspacedir) | ||
1179 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1180 | self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) | ||
1181 | result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) | ||
1182 | # Test that deploy-target at this point fails (properly) | ||
1183 | result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True) | ||
1184 | self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output) | ||
1185 | self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output) | ||
1186 | result = runCmd('devtool build %s' % testrecipe) | ||
1187 | # First try a dry-run of deploy-target | ||
1188 | result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe) | ||
1189 | self.assertIn(' %s' % testfile, result.output) | ||
1190 | # Boot the image | ||
1191 | with runqemu(testimage) as qemu: | ||
1192 | # Now really test deploy-target | ||
1193 | result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip)) | ||
1194 | # Run a test command to see if it was installed properly | ||
1195 | sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' | ||
1196 | result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand)) | ||
1197 | # Check if it deployed all of the files with the right ownership/perms | ||
1198 | # First look on the host - need to do this under pseudo to get the correct ownership/perms | ||
1199 | bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe) | ||
1200 | installdir = bb_vars['D'] | ||
1201 | fakerootenv = bb_vars['FAKEROOTENV'] | ||
1202 | fakerootcmd = bb_vars['FAKEROOTCMD'] | ||
1203 | result = runCmd('%s %s find . -type f -exec ls -l {} \;' % (fakerootenv, fakerootcmd), cwd=installdir) | ||
1204 | filelist1 = self._process_ls_output(result.output) | ||
1205 | |||
1206 | # Now look on the target | ||
1207 | tempdir2 = tempfile.mkdtemp(prefix='devtoolqa') | ||
1208 | self.track_for_cleanup(tempdir2) | ||
1209 | tmpfilelist = os.path.join(tempdir2, 'files.txt') | ||
1210 | with open(tmpfilelist, 'w') as f: | ||
1211 | for line in filelist1: | ||
1212 | splitline = line.split() | ||
1213 | f.write(splitline[-1] + '\n') | ||
1214 | result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip)) | ||
1215 | filelist2 = self._process_ls_output(result.output) | ||
1216 | filelist1.sort(key=lambda item: item.split()[-1]) | ||
1217 | filelist2.sort(key=lambda item: item.split()[-1]) | ||
1218 | self.assertEqual(filelist1, filelist2) | ||
1219 | # Test undeploy-target | ||
1220 | result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip)) | ||
1221 | result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True) | ||
1222 | self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have') | ||
1223 | |||
1224 | @OETestID(1366) | ||
1225 | def test_devtool_build_image(self): | ||
1226 | """Test devtool build-image plugin""" | ||
1227 | # Check preconditions | ||
1228 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
1229 | image = 'core-image-minimal' | ||
1230 | self.track_for_cleanup(self.workspacedir) | ||
1231 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1232 | self.add_command_to_tearDown('bitbake -c clean %s' % image) | ||
1233 | bitbake('%s -c clean' % image) | ||
1234 | # Add target and native recipes to workspace | ||
1235 | recipes = ['mdadm', 'parted-native'] | ||
1236 | for recipe in recipes: | ||
1237 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1238 | self.track_for_cleanup(tempdir) | ||
1239 | self.add_command_to_tearDown('bitbake -c clean %s' % recipe) | ||
1240 | runCmd('devtool modify %s -x %s' % (recipe, tempdir)) | ||
1241 | # Try to build image | ||
1242 | result = runCmd('devtool build-image %s' % image) | ||
1243 | self.assertNotEqual(result, 0, 'devtool build-image failed') | ||
1244 | # Check if image contains expected packages | ||
1245 | deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') | ||
1246 | image_link_name = get_bb_var('IMAGE_LINK_NAME', image) | ||
1247 | reqpkgs = [item for item in recipes if not item.endswith('-native')] | ||
1248 | with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f: | ||
1249 | for line in f: | ||
1250 | splitval = line.split() | ||
1251 | if splitval: | ||
1252 | pkg = splitval[0] | ||
1253 | if pkg in reqpkgs: | ||
1254 | reqpkgs.remove(pkg) | ||
1255 | if reqpkgs: | ||
1256 | self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs)) | ||
1257 | |||
1258 | @OETestID(1367) | ||
1259 | def test_devtool_upgrade(self): | ||
1260 | # Check preconditions | ||
1261 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
1262 | self.track_for_cleanup(self.workspacedir) | ||
1263 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1264 | # Check parameters | ||
1265 | result = runCmd('devtool upgrade -h') | ||
1266 | for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split(): | ||
1267 | self.assertIn(param, result.output) | ||
1268 | # For the moment, we are using a real recipe. | ||
1269 | recipe = 'devtool-upgrade-test1' | ||
1270 | version = '1.6.0' | ||
1271 | oldrecipefile = get_bb_var('FILE', recipe) | ||
1272 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1273 | self.track_for_cleanup(tempdir) | ||
1274 | # Check that recipe is not already under devtool control | ||
1275 | result = runCmd('devtool status') | ||
1276 | self.assertNotIn(recipe, result.output) | ||
1277 | # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that | ||
1278 | # we are downgrading instead of upgrading. | ||
1279 | result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version)) | ||
1280 | # Check if srctree at least is populated | ||
1281 | self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version)) | ||
1282 | # Check new recipe subdirectory is present | ||
1283 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version))), 'Recipe folder should exist') | ||
1284 | # Check new recipe file is present | ||
1285 | newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version)) | ||
1286 | self.assertTrue(os.path.exists(newrecipefile), 'Recipe file should exist after upgrade') | ||
1287 | # Check devtool status and make sure recipe is present | ||
1288 | result = runCmd('devtool status') | ||
1289 | self.assertIn(recipe, result.output) | ||
1290 | self.assertIn(tempdir, result.output) | ||
1291 | # Check recipe got changed as expected | ||
1292 | with open(oldrecipefile + '.upgraded', 'r') as f: | ||
1293 | desiredlines = f.readlines() | ||
1294 | with open(newrecipefile, 'r') as f: | ||
1295 | newlines = f.readlines() | ||
1296 | self.assertEqual(desiredlines, newlines) | ||
1297 | # Check devtool reset recipe | ||
1298 | result = runCmd('devtool reset %s -n' % recipe) | ||
1299 | result = runCmd('devtool status') | ||
1300 | self.assertNotIn(recipe, result.output) | ||
1301 | self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipe)), 'Recipe directory should not exist after resetting') | ||
1302 | |||
1303 | @OETestID(1433) | ||
1304 | def test_devtool_upgrade_git(self): | ||
1305 | # Check preconditions | ||
1306 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
1307 | self.track_for_cleanup(self.workspacedir) | ||
1308 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1309 | recipe = 'devtool-upgrade-test2' | ||
1310 | commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517' | ||
1311 | oldrecipefile = get_bb_var('FILE', recipe) | ||
1312 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1313 | self.track_for_cleanup(tempdir) | ||
1314 | # Check that recipe is not already under devtool control | ||
1315 | result = runCmd('devtool status') | ||
1316 | self.assertNotIn(recipe, result.output) | ||
1317 | # Check upgrade | ||
1318 | result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit)) | ||
1319 | # Check if srctree at least is populated | ||
1320 | self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit)) | ||
1321 | # Check new recipe file is present | ||
1322 | newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile)) | ||
1323 | self.assertTrue(os.path.exists(newrecipefile), 'Recipe file should exist after upgrade') | ||
1324 | # Check devtool status and make sure recipe is present | ||
1325 | result = runCmd('devtool status') | ||
1326 | self.assertIn(recipe, result.output) | ||
1327 | self.assertIn(tempdir, result.output) | ||
1328 | # Check recipe got changed as expected | ||
1329 | with open(oldrecipefile + '.upgraded', 'r') as f: | ||
1330 | desiredlines = f.readlines() | ||
1331 | with open(newrecipefile, 'r') as f: | ||
1332 | newlines = f.readlines() | ||
1333 | self.assertEqual(desiredlines, newlines) | ||
1334 | # Check devtool reset recipe | ||
1335 | result = runCmd('devtool reset %s -n' % recipe) | ||
1336 | result = runCmd('devtool status') | ||
1337 | self.assertNotIn(recipe, result.output) | ||
1338 | self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipe)), 'Recipe directory should not exist after resetting') | ||
1339 | |||
1340 | @OETestID(1352) | ||
1341 | def test_devtool_layer_plugins(self): | ||
1342 | """Test that devtool can use plugins from other layers. | ||
1343 | |||
1344 | This test executes the selftest-reverse command from meta-selftest.""" | ||
1345 | |||
1346 | self.track_for_cleanup(self.workspacedir) | ||
1347 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1348 | |||
1349 | s = "Microsoft Made No Profit From Anyone's Zunes Yo" | ||
1350 | result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s) | ||
1351 | self.assertEqual(result.output, s[::-1]) | ||
1352 | |||
1353 | def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths): | ||
1354 | dstdir = basedstdir | ||
1355 | self.assertTrue(os.path.exists(dstdir)) | ||
1356 | for p in paths: | ||
1357 | dstdir = os.path.join(dstdir, p) | ||
1358 | if not os.path.exists(dstdir): | ||
1359 | os.makedirs(dstdir) | ||
1360 | self.track_for_cleanup(dstdir) | ||
1361 | dstfile = os.path.join(dstdir, os.path.basename(srcfile)) | ||
1362 | if srcfile != dstfile: | ||
1363 | shutil.copy(srcfile, dstfile) | ||
1364 | self.track_for_cleanup(dstfile) | ||
1365 | |||
1366 | def test_devtool_load_plugin(self): | ||
1367 | """Test that devtool loads only the first found plugin in BBPATH.""" | ||
1368 | |||
1369 | self.track_for_cleanup(self.workspacedir) | ||
1370 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1371 | |||
1372 | devtool = runCmd("which devtool") | ||
1373 | fromname = runCmd("devtool --quiet pluginfile") | ||
1374 | srcfile = fromname.output | ||
1375 | bbpath = get_bb_var('BBPATH') | ||
1376 | searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)] | ||
1377 | plugincontent = [] | ||
1378 | with open(srcfile) as fh: | ||
1379 | plugincontent = fh.readlines() | ||
1380 | try: | ||
1381 | self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found') | ||
1382 | for path in searchpath: | ||
1383 | self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool') | ||
1384 | result = runCmd("devtool --quiet count") | ||
1385 | self.assertEqual(result.output, '1') | ||
1386 | result = runCmd("devtool --quiet multiloaded") | ||
1387 | self.assertEqual(result.output, "no") | ||
1388 | for path in searchpath: | ||
1389 | result = runCmd("devtool --quiet bbdir") | ||
1390 | self.assertEqual(result.output, path) | ||
1391 | os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py')) | ||
1392 | finally: | ||
1393 | with open(srcfile, 'w') as fh: | ||
1394 | fh.writelines(plugincontent) | ||
1395 | |||
1396 | def _setup_test_devtool_finish_upgrade(self): | ||
1397 | # Check preconditions | ||
1398 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
1399 | self.track_for_cleanup(self.workspacedir) | ||
1400 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1401 | # Use a "real" recipe from meta-selftest | ||
1402 | recipe = 'devtool-upgrade-test1' | ||
1403 | oldversion = '1.5.3' | ||
1404 | newversion = '1.6.0' | ||
1405 | oldrecipefile = get_bb_var('FILE', recipe) | ||
1406 | recipedir = os.path.dirname(oldrecipefile) | ||
1407 | result = runCmd('git status --porcelain .', cwd=recipedir) | ||
1408 | if result.output.strip(): | ||
1409 | self.fail('Recipe directory for %s contains uncommitted changes' % recipe) | ||
1410 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1411 | self.track_for_cleanup(tempdir) | ||
1412 | # Check that recipe is not already under devtool control | ||
1413 | result = runCmd('devtool status') | ||
1414 | self.assertNotIn(recipe, result.output) | ||
1415 | # Do the upgrade | ||
1416 | result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion)) | ||
1417 | # Check devtool status and make sure recipe is present | ||
1418 | result = runCmd('devtool status') | ||
1419 | self.assertIn(recipe, result.output) | ||
1420 | self.assertIn(tempdir, result.output) | ||
1421 | # Make a change to the source | ||
1422 | result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir) | ||
1423 | result = runCmd('git status --porcelain', cwd=tempdir) | ||
1424 | self.assertIn('M src/pv/number.c', result.output) | ||
1425 | result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir) | ||
1426 | # Check if patch is there | ||
1427 | recipedir = os.path.dirname(oldrecipefile) | ||
1428 | olddir = os.path.join(recipedir, recipe + '-' + oldversion) | ||
1429 | patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch' | ||
1430 | self.assertTrue(os.path.exists(os.path.join(olddir, patchfn)), 'Original patch file does not exist') | ||
1431 | return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn | ||
1432 | |||
1433 | def test_devtool_finish_upgrade_origlayer(self): | ||
1434 | recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade() | ||
1435 | # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things) | ||
1436 | self.assertIn('/meta-selftest/', recipedir) | ||
1437 | # Try finish to the original layer | ||
1438 | self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir)) | ||
1439 | result = runCmd('devtool finish %s meta-selftest' % recipe) | ||
1440 | result = runCmd('devtool status') | ||
1441 | self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t') | ||
1442 | self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipe)), 'Recipe directory should not exist after finish') | ||
1443 | self.assertFalse(os.path.exists(oldrecipefile), 'Old recipe file should have been deleted but wasn\'t') | ||
1444 | self.assertFalse(os.path.exists(os.path.join(olddir, patchfn)), 'Old patch file should have been deleted but wasn\'t') | ||
1445 | newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion)) | ||
1446 | newdir = os.path.join(recipedir, recipe + '-' + newversion) | ||
1447 | self.assertTrue(os.path.exists(newrecipefile), 'New recipe file should have been copied into existing layer but wasn\'t') | ||
1448 | self.assertTrue(os.path.exists(os.path.join(newdir, patchfn)), 'Patch file should have been copied into new directory but wasn\'t') | ||
1449 | self.assertTrue(os.path.exists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch')), 'New patch file should have been created but wasn\'t') | ||
1450 | |||
1451 | def test_devtool_finish_upgrade_otherlayer(self): | ||
1452 | recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade() | ||
1453 | # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things) | ||
1454 | self.assertIn('/meta-selftest/', recipedir) | ||
1455 | # Try finish to a different layer - should create a bbappend | ||
1456 | # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here | ||
1457 | self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir)) | ||
1458 | oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta') | ||
1459 | newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool') | ||
1460 | newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion)) | ||
1461 | self.track_for_cleanup(newrecipedir) | ||
1462 | result = runCmd('devtool finish %s oe-core' % recipe) | ||
1463 | result = runCmd('devtool status') | ||
1464 | self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t') | ||
1465 | self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipe)), 'Recipe directory should not exist after finish') | ||
1466 | self.assertTrue(os.path.exists(oldrecipefile), 'Old recipe file should not have been deleted') | ||
1467 | self.assertTrue(os.path.exists(os.path.join(olddir, patchfn)), 'Old patch file should not have been deleted') | ||
1468 | newdir = os.path.join(newrecipedir, recipe + '-' + newversion) | ||
1469 | self.assertTrue(os.path.exists(newrecipefile), 'New recipe file should have been copied into existing layer but wasn\'t') | ||
1470 | self.assertTrue(os.path.exists(os.path.join(newdir, patchfn)), 'Patch file should have been copied into new directory but wasn\'t') | ||
1471 | self.assertTrue(os.path.exists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch')), 'New patch file should have been created but wasn\'t') | ||
1472 | |||
1473 | def _setup_test_devtool_finish_modify(self): | ||
1474 | # Check preconditions | ||
1475 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
1476 | # Try modifying a recipe | ||
1477 | self.track_for_cleanup(self.workspacedir) | ||
1478 | recipe = 'mdadm' | ||
1479 | oldrecipefile = get_bb_var('FILE', recipe) | ||
1480 | recipedir = os.path.dirname(oldrecipefile) | ||
1481 | result = runCmd('git status --porcelain .', cwd=recipedir) | ||
1482 | if result.output.strip(): | ||
1483 | self.fail('Recipe directory for %s contains uncommitted changes' % recipe) | ||
1484 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1485 | self.track_for_cleanup(tempdir) | ||
1486 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1487 | result = runCmd('devtool modify %s %s' % (recipe, tempdir)) | ||
1488 | self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile')), 'Extracted source could not be found') | ||
1489 | # Test devtool status | ||
1490 | result = runCmd('devtool status') | ||
1491 | self.assertIn(recipe, result.output) | ||
1492 | self.assertIn(tempdir, result.output) | ||
1493 | # Make a change to the source | ||
1494 | result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir) | ||
1495 | result = runCmd('git status --porcelain', cwd=tempdir) | ||
1496 | self.assertIn('M maps.c', result.output) | ||
1497 | result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir) | ||
1498 | for entry in os.listdir(recipedir): | ||
1499 | filesdir = os.path.join(recipedir, entry) | ||
1500 | if os.path.isdir(filesdir): | ||
1501 | break | ||
1502 | else: | ||
1503 | self.fail('Unable to find recipe files directory for %s' % recipe) | ||
1504 | return recipe, oldrecipefile, recipedir, filesdir | ||
1505 | |||
1506 | def test_devtool_finish_modify_origlayer(self): | ||
1507 | recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify() | ||
1508 | # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things) | ||
1509 | self.assertIn('/meta/', recipedir) | ||
1510 | # Try finish to the original layer | ||
1511 | self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir)) | ||
1512 | result = runCmd('devtool finish %s meta' % recipe) | ||
1513 | result = runCmd('devtool status') | ||
1514 | self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t') | ||
1515 | self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipe)), 'Recipe directory should not exist after finish') | ||
1516 | expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)), | ||
1517 | ('??', '.*/.*-Add-a-comment-to-the-code.patch$')] | ||
1518 | self._check_repo_status(recipedir, expected_status) | ||
1519 | |||
1520 | def test_devtool_finish_modify_otherlayer(self): | ||
1521 | recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify() | ||
1522 | # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things) | ||
1523 | self.assertIn('/meta/', recipedir) | ||
1524 | relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta')) | ||
1525 | appenddir = os.path.join(get_test_layer(), relpth) | ||
1526 | self.track_for_cleanup(appenddir) | ||
1527 | # Try finish to the original layer | ||
1528 | self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir)) | ||
1529 | result = runCmd('devtool finish %s meta-selftest' % recipe) | ||
1530 | result = runCmd('devtool status') | ||
1531 | self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t') | ||
1532 | self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipe)), 'Recipe directory should not exist after finish') | ||
1533 | result = runCmd('git status --porcelain .', cwd=recipedir) | ||
1534 | if result.output.strip(): | ||
1535 | self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip())) | ||
1536 | recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0] | ||
1537 | recipefn = recipefn.split('_')[0] + '_%' | ||
1538 | appendfile = os.path.join(appenddir, recipefn + '.bbappend') | ||
1539 | self.assertTrue(os.path.exists(appendfile), 'bbappend %s should have been created but wasn\'t' % appendfile) | ||
1540 | newdir = os.path.join(appenddir, recipe) | ||
1541 | files = os.listdir(newdir) | ||
1542 | foundpatch = None | ||
1543 | for fn in files: | ||
1544 | if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'): | ||
1545 | foundpatch = fn | ||
1546 | if not foundpatch: | ||
1547 | self.fail('No patch file created next to bbappend') | ||
1548 | files.remove(foundpatch) | ||
1549 | if files: | ||
1550 | self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files)) | ||
1551 | |||
1552 | def test_devtool_rename(self): | ||
1553 | # Check preconditions | ||
1554 | self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory') | ||
1555 | self.track_for_cleanup(self.workspacedir) | ||
1556 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1557 | |||
1558 | # First run devtool add | ||
1559 | # We already have this recipe in OE-Core, but that doesn't matter | ||
1560 | recipename = 'i2c-tools' | ||
1561 | recipever = '3.1.2' | ||
1562 | recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever)) | ||
1563 | url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever | ||
1564 | def add_recipe(): | ||
1565 | result = runCmd('devtool add %s' % url) | ||
1566 | self.assertTrue(os.path.exists(recipefile), 'Expected recipe file not created') | ||
1567 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'sources', recipename)), 'Source directory not created') | ||
1568 | checkvars = {} | ||
1569 | checkvars['S'] = None | ||
1570 | checkvars['SRC_URI'] = url.replace(recipever, '${PV}') | ||
1571 | self._test_recipe_contents(recipefile, checkvars, []) | ||
1572 | add_recipe() | ||
1573 | # Now rename it - change both name and version | ||
1574 | newrecipename = 'mynewrecipe' | ||
1575 | newrecipever = '456' | ||
1576 | newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever)) | ||
1577 | result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever)) | ||
1578 | self.assertTrue(os.path.exists(newrecipefile), 'Recipe file not renamed') | ||
1579 | self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipename)), 'Old recipe directory still exists') | ||
1580 | newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename) | ||
1581 | self.assertTrue(os.path.exists(newsrctree), 'Source directory not renamed') | ||
1582 | checkvars = {} | ||
1583 | checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever) | ||
1584 | checkvars['SRC_URI'] = url | ||
1585 | self._test_recipe_contents(newrecipefile, checkvars, []) | ||
1586 | # Try again - change just name this time | ||
1587 | result = runCmd('devtool reset -n %s' % newrecipename) | ||
1588 | shutil.rmtree(newsrctree) | ||
1589 | add_recipe() | ||
1590 | newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever)) | ||
1591 | result = runCmd('devtool rename %s %s' % (recipename, newrecipename)) | ||
1592 | self.assertTrue(os.path.exists(newrecipefile), 'Recipe file not renamed') | ||
1593 | self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipename)), 'Old recipe directory still exists') | ||
1594 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'sources', newrecipename)), 'Source directory not renamed') | ||
1595 | checkvars = {} | ||
1596 | checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename | ||
1597 | checkvars['SRC_URI'] = url.replace(recipever, '${PV}') | ||
1598 | self._test_recipe_contents(newrecipefile, checkvars, []) | ||
1599 | # Try again - change just version this time | ||
1600 | result = runCmd('devtool reset -n %s' % newrecipename) | ||
1601 | shutil.rmtree(newsrctree) | ||
1602 | add_recipe() | ||
1603 | newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever)) | ||
1604 | result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever)) | ||
1605 | self.assertTrue(os.path.exists(newrecipefile), 'Recipe file not renamed') | ||
1606 | self.assertTrue(os.path.exists(os.path.join(self.workspacedir, 'sources', recipename)), 'Source directory no longer exists') | ||
1607 | checkvars = {} | ||
1608 | checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever | ||
1609 | checkvars['SRC_URI'] = url | ||
1610 | self._test_recipe_contents(newrecipefile, checkvars, []) | ||
1611 | |||
1612 | @OETestID(1577) | ||
1613 | def test_devtool_virtual_kernel_modify(self): | ||
1614 | """ | ||
1615 | Summary: The purpose of this test case is to verify that | ||
1616 | devtool modify works correctly when building | ||
1617 | the kernel. | ||
1618 | Dependencies: NA | ||
1619 | Steps: 1. Build kernel with bitbake. | ||
1620 | 2. Save the config file generated. | ||
1621 | 3. Clean the environment. | ||
1622 | 4. Use `devtool modify virtual/kernel` to validate following: | ||
1623 | 4.1 The source is checked out correctly. | ||
1624 | 4.2 The resulting configuration is the same as | ||
1625 | what was get on step 2. | ||
1626 | 4.3 The Kernel can be build correctly. | ||
1627 | 4.4 Changes made on the source are reflected on the | ||
1628 | subsequent builds. | ||
1629 | 4.5 Changes on the configuration are reflected on the | ||
1630 | subsequent builds | ||
1631 | Expected: devtool modify is able to checkout the source of the kernel | ||
1632 | and modification to the source and configurations are reflected | ||
1633 | when building the kernel. | ||
1634 | """ | ||
1635 | #Set machine to qemxu86 to be able to modify the kernel and | ||
1636 | #verify the modification. | ||
1637 | features = 'MACHINE = "qemux86"\n' | ||
1638 | self.append_config(features) | ||
1639 | kernel_provider = get_bb_var('PREFERRED_PROVIDER_virtual/kernel') | ||
1640 | # Clean up the enviroment | ||
1641 | bitbake('%s -c clean' % kernel_provider) | ||
1642 | tempdir = tempfile.mkdtemp(prefix='devtoolqa') | ||
1643 | self.track_for_cleanup(tempdir) | ||
1644 | self.track_for_cleanup(self.workspacedir) | ||
1645 | self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') | ||
1646 | self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider) | ||
1647 | #Step 1 | ||
1648 | #Here is just generated the config file instead of all the kernel to optimize the | ||
1649 | #time of executing this test case. | ||
1650 | bitbake('%s -c configure' % kernel_provider) | ||
1651 | bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config') | ||
1652 | buildir= get_bb_var('TOPDIR') | ||
1653 | #Step 2 | ||
1654 | runCmd('cp %s %s' % (bbconfig, buildir)) | ||
1655 | self.assertTrue(os.path.exists(os.path.join(buildir, '.config')), | ||
1656 | 'Could not copy .config file from kernel') | ||
1657 | |||
1658 | tmpconfig = os.path.join(buildir, '.config') | ||
1659 | #Step 3 | ||
1660 | bitbake('%s -c clean' % kernel_provider) | ||
1661 | #Step 4.1 | ||
1662 | runCmd('devtool modify virtual/kernel -x %s' % tempdir) | ||
1663 | self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile')), | ||
1664 | 'Extracted source could not be found') | ||
1665 | #Step 4.2 | ||
1666 | configfile = os.path.join(tempdir,'.config') | ||
1667 | diff = runCmd('diff %s %s' % (tmpconfig, configfile)) | ||
1668 | self.assertEqual(0,diff.status,'Kernel .config file is not the same using bitbake and devtool') | ||
1669 | #Step 4.3 | ||
1670 | #NOTE: virtual/kernel is mapped to kernel_provider | ||
1671 | result = runCmd('devtool build %s' % kernel_provider) | ||
1672 | self.assertEqual(0,result.status,'Cannot build kernel using `devtool build`') | ||
1673 | kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux') | ||
1674 | self.assertTrue(os.path.exists(kernelfile),'Kernel was not build correctly') | ||
1675 | |||
1676 | #Modify the kernel source, this is specific for qemux86 | ||
1677 | modfile = os.path.join(tempdir,'arch/x86/boot/header.S') | ||
1678 | modstring = "use a boot loader - Devtool kernel testing" | ||
1679 | modapplied = runCmd("sed -i 's/boot loader/%s/' %s" % (modstring, modfile)) | ||
1680 | self.assertEqual(0,modapplied.status,'Modification to %s on kernel source failed' % modfile) | ||
1681 | #Modify the configuration | ||
1682 | codeconfigfile = os.path.join(tempdir,'.config.new') | ||
1683 | modconfopt = "CONFIG_SG_POOL=n" | ||
1684 | modconf = runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile)) | ||
1685 | self.assertEqual(0,modconf.status,'Modification to %s failed' % codeconfigfile) | ||
1686 | #Build again kernel with devtool | ||
1687 | rebuild = runCmd('devtool build %s' % kernel_provider) | ||
1688 | self.assertEqual(0,rebuild.status,'Fail to build kernel after modification of source and config') | ||
1689 | #Step 4.4 | ||
1690 | bzimagename = 'bzImage-' + get_bb_var('KERNEL_VERSION_NAME', kernel_provider) | ||
1691 | bzimagefile = os.path.join(get_bb_var('D', kernel_provider),'boot', bzimagename) | ||
1692 | checkmodcode = runCmd("grep '%s' %s" % (modstring, bzimagefile)) | ||
1693 | self.assertEqual(0,checkmodcode.status,'Modification on kernel source failed') | ||
1694 | #Step 4.5 | ||
1695 | checkmodconfg = runCmd("grep %s %s" % (modconfopt, codeconfigfile)) | ||
1696 | self.assertEqual(0,checkmodconfg.status,'Modification to configuration file failed') | ||