summaryrefslogtreecommitdiffstats
path: root/meta/lib/oeqa/selftest
diff options
context:
space:
mode:
authorPaul Eggleton <paul.eggleton@linux.intel.com>2016-07-14 09:04:25 +1200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-07-20 10:28:49 +0100
commitd62fd7711d508a4bd926e46a235d2511401f543d (patch)
tree9968d72a87dc9176a45a7c2b596a2b71404f6753 /meta/lib/oeqa/selftest
parent10a5af5eb4f928abe1fe12e63520f656b682d55d (diff)
downloadpoky-d62fd7711d508a4bd926e46a235d2511401f543d.tar.gz
devtool: add finish subcommand
Add a subcommand which will "finish" the work on a recipe. This is effectively the same as update-recipe followed by reset, except that the destination layer is required and it will do the right thing depending on the situation - if the recipe file itself is in the workspace (e.g. as a result of devtool add), the recipe file and any associated files will be moved to the destination layer; or if the destination layer is the one containing the original recipe, the recipe will be overwritten; otherwise a bbappend will be created to apply the changes. In all cases the layer path can be loosely specified - it could be a layer name, or a partial path into a recipe. In the case of upgrades, devtool finish will also take care of deleting the old recipe. This avoids the user having to figure out the correct actions when they're done - they just do "devtool finish recipename layername" and it saves their work and then removes the recipe from the workspace. Addresses [YOCTO #8594]. (From OE-Core rev: fa550fcb9333d59b28fc0e4aebde888831410f5c) Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> Signed-off-by: Ross Burton <ross.burton@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib/oeqa/selftest')
-rw-r--r--meta/lib/oeqa/selftest/devtool.py157
1 files changed, 156 insertions, 1 deletions
diff --git a/meta/lib/oeqa/selftest/devtool.py b/meta/lib/oeqa/selftest/devtool.py
index 0b305c893e..974333f555 100644
--- a/meta/lib/oeqa/selftest/devtool.py
+++ b/meta/lib/oeqa/selftest/devtool.py
@@ -5,10 +5,11 @@ import re
5import shutil 5import shutil
6import tempfile 6import tempfile
7import glob 7import glob
8import fnmatch
8 9
9import oeqa.utils.ftools as ftools 10import oeqa.utils.ftools as ftools
10from oeqa.selftest.base import oeSelfTest 11from oeqa.selftest.base import oeSelfTest
11from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer, runqemu 12from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer, runqemu, get_test_layer
12from oeqa.utils.decorators import testcase 13from oeqa.utils.decorators import testcase
13 14
14class DevtoolBase(oeSelfTest): 15class DevtoolBase(oeSelfTest):
@@ -1189,3 +1190,157 @@ class DevtoolTests(DevtoolBase):
1189 s = "Microsoft Made No Profit From Anyone's Zunes Yo" 1190 s = "Microsoft Made No Profit From Anyone's Zunes Yo"
1190 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s) 1191 result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
1191 self.assertEqual(result.output, s[::-1]) 1192 self.assertEqual(result.output, s[::-1])
1193
1194 def _setup_test_devtool_finish_upgrade(self):
1195 # Check preconditions
1196 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1197 self.track_for_cleanup(self.workspacedir)
1198 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1199 # Use a "real" recipe from meta-selftest
1200 recipe = 'devtool-upgrade-test1'
1201 oldversion = '1.5.3'
1202 newversion = '1.6.0'
1203 oldrecipefile = get_bb_var('FILE', recipe)
1204 recipedir = os.path.dirname(oldrecipefile)
1205 result = runCmd('git status --porcelain .', cwd=recipedir)
1206 if result.output.strip():
1207 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1208 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1209 self.track_for_cleanup(tempdir)
1210 # Check that recipe is not already under devtool control
1211 result = runCmd('devtool status')
1212 self.assertNotIn(recipe, result.output)
1213 # Do the upgrade
1214 result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
1215 # Check devtool status and make sure recipe is present
1216 result = runCmd('devtool status')
1217 self.assertIn(recipe, result.output)
1218 self.assertIn(tempdir, result.output)
1219 # Make a change to the source
1220 result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
1221 result = runCmd('git status --porcelain', cwd=tempdir)
1222 self.assertIn('M src/pv/number.c', result.output)
1223 result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
1224 # Check if patch is there
1225 recipedir = os.path.dirname(oldrecipefile)
1226 olddir = os.path.join(recipedir, recipe + '-' + oldversion)
1227 patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
1228 self.assertTrue(os.path.exists(os.path.join(olddir, patchfn)), 'Original patch file does not exist')
1229 return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn
1230
1231 def test_devtool_finish_upgrade_origlayer(self):
1232 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade()
1233 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1234 self.assertIn('/meta-selftest/', recipedir)
1235 # Try finish to the original layer
1236 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1237 result = runCmd('devtool finish %s meta-selftest' % recipe)
1238 result = runCmd('devtool status')
1239 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1240 self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipe)), 'Recipe directory should not exist after finish')
1241 self.assertFalse(os.path.exists(oldrecipefile), 'Old recipe file should have been deleted but wasn\'t')
1242 self.assertFalse(os.path.exists(os.path.join(olddir, patchfn)), 'Old patch file should have been deleted but wasn\'t')
1243 newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
1244 newdir = os.path.join(recipedir, recipe + '-' + newversion)
1245 self.assertTrue(os.path.exists(newrecipefile), 'New recipe file should have been copied into existing layer but wasn\'t')
1246 self.assertTrue(os.path.exists(os.path.join(newdir, patchfn)), 'Patch file should have been copied into new directory but wasn\'t')
1247 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')
1248
1249 def test_devtool_finish_upgrade_otherlayer(self):
1250 recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade()
1251 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1252 self.assertIn('/meta-selftest/', recipedir)
1253 # Try finish to a different layer - should create a bbappend
1254 # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
1255 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1256 oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
1257 newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
1258 newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
1259 self.track_for_cleanup(newrecipedir)
1260 result = runCmd('devtool finish %s oe-core' % recipe)
1261 result = runCmd('devtool status')
1262 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1263 self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipe)), 'Recipe directory should not exist after finish')
1264 self.assertTrue(os.path.exists(oldrecipefile), 'Old recipe file should not have been deleted')
1265 self.assertTrue(os.path.exists(os.path.join(olddir, patchfn)), 'Old patch file should not have been deleted')
1266 newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
1267 self.assertTrue(os.path.exists(newrecipefile), 'New recipe file should have been copied into existing layer but wasn\'t')
1268 self.assertTrue(os.path.exists(os.path.join(newdir, patchfn)), 'Patch file should have been copied into new directory but wasn\'t')
1269 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')
1270
1271 def _setup_test_devtool_finish_modify(self):
1272 # Check preconditions
1273 self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
1274 # Try modifying a recipe
1275 self.track_for_cleanup(self.workspacedir)
1276 recipe = 'mdadm'
1277 oldrecipefile = get_bb_var('FILE', recipe)
1278 recipedir = os.path.dirname(oldrecipefile)
1279 result = runCmd('git status --porcelain .', cwd=recipedir)
1280 if result.output.strip():
1281 self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
1282 tempdir = tempfile.mkdtemp(prefix='devtoolqa')
1283 self.track_for_cleanup(tempdir)
1284 self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
1285 result = runCmd('devtool modify %s %s' % (recipe, tempdir))
1286 self.assertTrue(os.path.exists(os.path.join(tempdir, 'Makefile')), 'Extracted source could not be found')
1287 # Test devtool status
1288 result = runCmd('devtool status')
1289 self.assertIn(recipe, result.output)
1290 self.assertIn(tempdir, result.output)
1291 # Make a change to the source
1292 result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
1293 result = runCmd('git status --porcelain', cwd=tempdir)
1294 self.assertIn('M maps.c', result.output)
1295 result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
1296 for entry in os.listdir(recipedir):
1297 filesdir = os.path.join(recipedir, entry)
1298 if os.path.isdir(filesdir):
1299 break
1300 else:
1301 self.fail('Unable to find recipe files directory for %s' % recipe)
1302 return recipe, oldrecipefile, recipedir, filesdir
1303
1304 def test_devtool_finish_modify_origlayer(self):
1305 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1306 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1307 self.assertIn('/meta/', recipedir)
1308 # Try finish to the original layer
1309 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1310 result = runCmd('devtool finish %s meta' % recipe)
1311 result = runCmd('devtool status')
1312 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1313 self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipe)), 'Recipe directory should not exist after finish')
1314 expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
1315 ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
1316 self._check_repo_status(recipedir, expected_status)
1317
1318 def test_devtool_finish_modify_otherlayer(self):
1319 recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
1320 # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
1321 self.assertIn('/meta/', recipedir)
1322 relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
1323 appenddir = os.path.join(get_test_layer(), relpth)
1324 self.track_for_cleanup(appenddir)
1325 # Try finish to the original layer
1326 self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
1327 result = runCmd('devtool finish %s meta-selftest' % recipe)
1328 result = runCmd('devtool status')
1329 self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
1330 self.assertFalse(os.path.exists(os.path.join(self.workspacedir, 'recipes', recipe)), 'Recipe directory should not exist after finish')
1331 result = runCmd('git status --porcelain .', cwd=recipedir)
1332 if result.output.strip():
1333 self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
1334 appendfile = os.path.join(appenddir, os.path.splitext(os.path.basename(oldrecipefile))[0] + '.bbappend')
1335 self.assertTrue(os.path.exists(appendfile), 'bbappend %s should have been created but wasn\'t' % appendfile)
1336 newdir = os.path.join(appenddir, recipe)
1337 files = os.listdir(newdir)
1338 foundpatch = None
1339 for fn in files:
1340 if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
1341 foundpatch = fn
1342 if not foundpatch:
1343 self.fail('No patch file created next to bbappend')
1344 files.remove(foundpatch)
1345 if files:
1346 self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))