diff options
| -rw-r--r-- | meta/lib/oe/recipeutils.py | 57 | ||||
| -rw-r--r-- | meta/lib/oeqa/selftest/devtool.py | 157 | ||||
| -rw-r--r-- | scripts/lib/devtool/standard.py | 111 |
3 files changed, 322 insertions, 3 deletions
diff --git a/meta/lib/oe/recipeutils.py b/meta/lib/oe/recipeutils.py index b8d481aeb8..0e7abf833b 100644 --- a/meta/lib/oe/recipeutils.py +++ b/meta/lib/oe/recipeutils.py | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | # | 2 | # |
| 3 | # Some code borrowed from the OE layer index | 3 | # Some code borrowed from the OE layer index |
| 4 | # | 4 | # |
| 5 | # Copyright (C) 2013-2015 Intel Corporation | 5 | # Copyright (C) 2013-2016 Intel Corporation |
| 6 | # | 6 | # |
| 7 | 7 | ||
| 8 | import sys | 8 | import sys |
| @@ -15,6 +15,7 @@ from . import utils | |||
| 15 | import shutil | 15 | import shutil |
| 16 | import re | 16 | import re |
| 17 | import fnmatch | 17 | import fnmatch |
| 18 | import glob | ||
| 18 | from collections import OrderedDict, defaultdict | 19 | from collections import OrderedDict, defaultdict |
| 19 | 20 | ||
| 20 | 21 | ||
| @@ -450,6 +451,60 @@ def validate_pn(pn): | |||
| 450 | return '' | 451 | return '' |
| 451 | 452 | ||
| 452 | 453 | ||
| 454 | def get_bbfile_path(d, destdir, extrapathhint=None): | ||
| 455 | """ | ||
| 456 | Determine the correct path for a recipe within a layer | ||
| 457 | Parameters: | ||
| 458 | d: Recipe-specific datastore | ||
| 459 | destdir: destination directory. Can be the path to the base of the layer or a | ||
| 460 | partial path somewhere within the layer. | ||
| 461 | extrapathhint: a path relative to the base of the layer to try | ||
| 462 | """ | ||
| 463 | import bb.cookerdata | ||
| 464 | |||
| 465 | destdir = os.path.abspath(destdir) | ||
| 466 | destlayerdir = find_layerdir(destdir) | ||
| 467 | |||
| 468 | # Parse the specified layer's layer.conf file directly, in case the layer isn't in bblayers.conf | ||
| 469 | confdata = d.createCopy() | ||
| 470 | confdata.setVar('BBFILES', '') | ||
| 471 | confdata.setVar('LAYERDIR', destlayerdir) | ||
| 472 | destlayerconf = os.path.join(destlayerdir, "conf", "layer.conf") | ||
| 473 | confdata = bb.cookerdata.parse_config_file(destlayerconf, confdata) | ||
| 474 | pn = d.getVar('PN', True) | ||
| 475 | |||
| 476 | bbfilespecs = (confdata.getVar('BBFILES', True) or '').split() | ||
| 477 | if destdir == destlayerdir: | ||
| 478 | for bbfilespec in bbfilespecs: | ||
| 479 | if not bbfilespec.endswith('.bbappend'): | ||
| 480 | for match in glob.glob(bbfilespec): | ||
| 481 | splitext = os.path.splitext(os.path.basename(match)) | ||
| 482 | if splitext[1] == '.bb': | ||
| 483 | mpn = splitext[0].split('_')[0] | ||
| 484 | if mpn == pn: | ||
| 485 | return os.path.dirname(match) | ||
| 486 | |||
| 487 | # Try to make up a path that matches BBFILES | ||
| 488 | # this is a little crude, but better than nothing | ||
| 489 | bpn = d.getVar('BPN', True) | ||
| 490 | recipefn = os.path.basename(d.getVar('FILE', True)) | ||
| 491 | pathoptions = [destdir] | ||
| 492 | if extrapathhint: | ||
| 493 | pathoptions.append(os.path.join(destdir, extrapathhint)) | ||
| 494 | if destdir == destlayerdir: | ||
| 495 | pathoptions.append(os.path.join(destdir, 'recipes-%s' % bpn, bpn)) | ||
| 496 | pathoptions.append(os.path.join(destdir, 'recipes', bpn)) | ||
| 497 | pathoptions.append(os.path.join(destdir, bpn)) | ||
| 498 | elif not destdir.endswith(('/' + pn, '/' + bpn)): | ||
| 499 | pathoptions.append(os.path.join(destdir, bpn)) | ||
| 500 | closepath = '' | ||
| 501 | for pathoption in pathoptions: | ||
| 502 | bbfilepath = os.path.join(pathoption, 'test.bb') | ||
| 503 | for bbfilespec in bbfilespecs: | ||
| 504 | if fnmatch.fnmatchcase(bbfilepath, bbfilespec): | ||
| 505 | return pathoption | ||
| 506 | return None | ||
| 507 | |||
| 453 | def get_bbappend_path(d, destlayerdir, wildcardver=False): | 508 | def get_bbappend_path(d, destlayerdir, wildcardver=False): |
| 454 | """Determine how a bbappend for a recipe should be named and located within another layer""" | 509 | """Determine how a bbappend for a recipe should be named and located within another layer""" |
| 455 | 510 | ||
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 | |||
| 5 | import shutil | 5 | import shutil |
| 6 | import tempfile | 6 | import tempfile |
| 7 | import glob | 7 | import glob |
| 8 | import fnmatch | ||
| 8 | 9 | ||
| 9 | import oeqa.utils.ftools as ftools | 10 | import oeqa.utils.ftools as ftools |
| 10 | from oeqa.selftest.base import oeSelfTest | 11 | from oeqa.selftest.base import oeSelfTest |
| 11 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer, runqemu | 12 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer, runqemu, get_test_layer |
| 12 | from oeqa.utils.decorators import testcase | 13 | from oeqa.utils.decorators import testcase |
| 13 | 14 | ||
| 14 | class DevtoolBase(oeSelfTest): | 15 | class 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)) | ||
diff --git a/scripts/lib/devtool/standard.py b/scripts/lib/devtool/standard.py index 5a5995f664..9c09533b54 100644 --- a/scripts/lib/devtool/standard.py +++ b/scripts/lib/devtool/standard.py | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | # Development tool - standard commands plugin | 1 | # Development tool - standard commands plugin |
| 2 | # | 2 | # |
| 3 | # Copyright (C) 2014-2015 Intel Corporation | 3 | # Copyright (C) 2014-2016 Intel Corporation |
| 4 | # | 4 | # |
| 5 | # This program is free software; you can redistribute it and/or modify | 5 | # This program is free software; you can redistribute it and/or modify |
| 6 | # it under the terms of the GNU General Public License version 2 as | 6 | # it under the terms of the GNU General Public License version 2 as |
| @@ -1394,6 +1394,106 @@ def reset(args, config, basepath, workspace): | |||
| 1394 | return 0 | 1394 | return 0 |
| 1395 | 1395 | ||
| 1396 | 1396 | ||
| 1397 | def _get_layer(layername, d): | ||
| 1398 | """Determine the base layer path for the specified layer name/path""" | ||
| 1399 | layerdirs = d.getVar('BBLAYERS', True).split() | ||
| 1400 | layers = {os.path.basename(p): p for p in layerdirs} | ||
| 1401 | # Provide some shortcuts | ||
| 1402 | if layername.lower() in ['oe-core', 'openembedded-core']: | ||
| 1403 | layerdir = layers.get('meta', None) | ||
| 1404 | else: | ||
| 1405 | layerdir = layers.get(layername, None) | ||
| 1406 | if layerdir: | ||
| 1407 | layerdir = os.path.abspath(layerdir) | ||
| 1408 | return layerdir or layername | ||
| 1409 | |||
| 1410 | def finish(args, config, basepath, workspace): | ||
| 1411 | """Entry point for the devtool 'finish' subcommand""" | ||
| 1412 | import bb | ||
| 1413 | import oe.recipeutils | ||
| 1414 | |||
| 1415 | check_workspace_recipe(workspace, args.recipename) | ||
| 1416 | |||
| 1417 | tinfoil = setup_tinfoil(basepath=basepath, tracking=True) | ||
| 1418 | try: | ||
| 1419 | rd = parse_recipe(config, tinfoil, args.recipename, True) | ||
| 1420 | if not rd: | ||
| 1421 | return 1 | ||
| 1422 | |||
| 1423 | destlayerdir = _get_layer(args.destination, tinfoil.config_data) | ||
| 1424 | origlayerdir = oe.recipeutils.find_layerdir(rd.getVar('FILE', True)) | ||
| 1425 | |||
| 1426 | if not os.path.isdir(destlayerdir): | ||
| 1427 | raise DevtoolError('Unable to find layer or directory matching "%s"' % args.destination) | ||
| 1428 | |||
| 1429 | if os.path.abspath(destlayerdir) == config.workspace_path: | ||
| 1430 | raise DevtoolError('"%s" specifies the workspace layer - that is not a valid destination' % args.destination) | ||
| 1431 | |||
| 1432 | # If it's an upgrade, grab the original path | ||
| 1433 | origpath = None | ||
| 1434 | origfilelist = None | ||
| 1435 | append = workspace[args.recipename]['bbappend'] | ||
| 1436 | with open(append, 'r') as f: | ||
| 1437 | for line in f: | ||
| 1438 | if line.startswith('# original_path:'): | ||
| 1439 | origpath = line.split(':')[1].strip() | ||
| 1440 | elif line.startswith('# original_files:'): | ||
| 1441 | origfilelist = line.split(':')[1].split() | ||
| 1442 | |||
| 1443 | if origlayerdir == config.workspace_path: | ||
| 1444 | # Recipe file itself is in workspace, update it there first | ||
| 1445 | appendlayerdir = None | ||
| 1446 | origrelpath = None | ||
| 1447 | if origpath: | ||
| 1448 | origlayerpath = oe.recipeutils.find_layerdir(origpath) | ||
| 1449 | if origlayerpath: | ||
| 1450 | origrelpath = os.path.relpath(origpath, origlayerpath) | ||
| 1451 | destpath = oe.recipeutils.get_bbfile_path(rd, destlayerdir, origrelpath) | ||
| 1452 | if not destpath: | ||
| 1453 | raise DevtoolError("Unable to determine destination layer path - check that %s specifies an actual layer and %s/conf/layer.conf specifies BBFILES. You may also need to specify a more complete path." % (args.destination, destlayerdir)) | ||
| 1454 | elif destlayerdir == origlayerdir: | ||
| 1455 | # Same layer, update the original recipe | ||
| 1456 | appendlayerdir = None | ||
| 1457 | destpath = None | ||
| 1458 | else: | ||
| 1459 | # Create/update a bbappend in the specified layer | ||
| 1460 | appendlayerdir = destlayerdir | ||
| 1461 | destpath = None | ||
| 1462 | |||
| 1463 | # Remove any old files in the case of an upgrade | ||
| 1464 | if origpath and origfilelist and oe.recipeutils.find_layerdir(origpath) == oe.recipeutils.find_layerdir(destlayerdir): | ||
| 1465 | for fn in origfilelist: | ||
| 1466 | fnp = os.path.join(origpath, fn) | ||
| 1467 | try: | ||
| 1468 | os.remove(fnp) | ||
| 1469 | except FileNotFoundError: | ||
| 1470 | pass | ||
| 1471 | |||
| 1472 | # Actually update the recipe / bbappend | ||
| 1473 | _update_recipe(args.recipename, workspace, rd, args.mode, appendlayerdir, wildcard_version=True, no_remove=False, initial_rev=args.initial_rev) | ||
| 1474 | |||
| 1475 | if origlayerdir == config.workspace_path and destpath: | ||
| 1476 | # Recipe file itself is in the workspace - need to move it and any | ||
| 1477 | # associated files to the specified layer | ||
| 1478 | logger.info('Moving recipe file to %s' % destpath) | ||
| 1479 | recipedir = os.path.dirname(rd.getVar('FILE', True)) | ||
| 1480 | for root, _, files in os.walk(recipedir): | ||
| 1481 | for fn in files: | ||
| 1482 | srcpath = os.path.join(root, fn) | ||
| 1483 | relpth = os.path.relpath(os.path.dirname(srcpath), recipedir) | ||
| 1484 | destdir = os.path.abspath(os.path.join(destpath, relpth)) | ||
| 1485 | bb.utils.mkdirhier(destdir) | ||
| 1486 | shutil.move(srcpath, os.path.join(destdir, fn)) | ||
| 1487 | |||
| 1488 | finally: | ||
| 1489 | tinfoil.shutdown() | ||
| 1490 | |||
| 1491 | # Everything else has succeeded, we can now reset | ||
| 1492 | _reset([args.recipename], no_clean=False, config=config, basepath=basepath, workspace=workspace) | ||
| 1493 | |||
| 1494 | return 0 | ||
| 1495 | |||
| 1496 | |||
| 1397 | def get_default_srctree(config, recipename=''): | 1497 | def get_default_srctree(config, recipename=''): |
| 1398 | """Get the default srctree path""" | 1498 | """Get the default srctree path""" |
| 1399 | srctreeparent = config.get('General', 'default_source_parent_dir', config.workspace_path) | 1499 | srctreeparent = config.get('General', 'default_source_parent_dir', config.workspace_path) |
| @@ -1481,3 +1581,12 @@ def register_commands(subparsers, context): | |||
| 1481 | parser_reset.add_argument('--all', '-a', action="store_true", help='Reset all recipes (clear workspace)') | 1581 | parser_reset.add_argument('--all', '-a', action="store_true", help='Reset all recipes (clear workspace)') |
| 1482 | parser_reset.add_argument('--no-clean', '-n', action="store_true", help='Don\'t clean the sysroot to remove recipe output') | 1582 | parser_reset.add_argument('--no-clean', '-n', action="store_true", help='Don\'t clean the sysroot to remove recipe output') |
| 1483 | parser_reset.set_defaults(func=reset) | 1583 | parser_reset.set_defaults(func=reset) |
| 1584 | |||
| 1585 | parser_finish = subparsers.add_parser('finish', help='Finish working on a recipe in your workspace', | ||
| 1586 | description='Pushes any committed changes to the specified recipe to the specified layer and removes it from your workspace. Roughly equivalent to an update-recipe followed by reset, except the update-recipe step will do the "right thing" depending on the recipe and the destination layer specified.', | ||
| 1587 | group='working', order=-100) | ||
| 1588 | parser_finish.add_argument('recipename', help='Recipe to finish') | ||
| 1589 | parser_finish.add_argument('destination', help='Layer/path to put recipe into. Can be the name of a layer configured in your bblayers.conf, the path to the base of a layer, or a partial path inside a layer. %(prog)s will attempt to complete the path based on the layer\'s structure.') | ||
| 1590 | parser_finish.add_argument('--mode', '-m', choices=['patch', 'srcrev', 'auto'], default='auto', help='Update mode (where %(metavar)s is %(choices)s; default is %(default)s)', metavar='MODE') | ||
| 1591 | parser_finish.add_argument('--initial-rev', help='Override starting revision for patches') | ||
| 1592 | parser_finish.set_defaults(func=finish) | ||
