diff options
author | Paul Eggleton <paul.eggleton@linux.intel.com> | 2017-11-01 11:56:18 +1300 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2017-11-11 12:14:27 +0000 |
commit | 9a80078e4b8e01d9bb49288f214f40e8497aa3ac (patch) | |
tree | ad8387c4352dd3e0d81cda000ad9452e0449d4e7 /scripts/lib | |
parent | d906d7cea814de917baf70eb3ecb568862fbc363 (diff) | |
download | poky-9a80078e4b8e01d9bb49288f214f40e8497aa3ac.tar.gz |
devtool: finish: add dry-run option
If you're not sure what changes devtool finish is going to make, or
you're not sure you're finished with your modifications, it is useful to
be able to see what devtool finish is going to do beforehand, so add
a -N/--dry-run option to make that possible.
(It's also very useful for debugging devtool finish itself.)
(From OE-Core rev: 05f2d5d2ce00c53825ccea5cd9c2262f9d27a638)
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 'scripts/lib')
-rw-r--r-- | scripts/lib/devtool/standard.py | 270 |
1 files changed, 199 insertions, 71 deletions
diff --git a/scripts/lib/devtool/standard.py b/scripts/lib/devtool/standard.py index 9d9031c2b3..d55d504a14 100644 --- a/scripts/lib/devtool/standard.py +++ b/scripts/lib/devtool/standard.py | |||
@@ -341,19 +341,45 @@ def _check_compatible_recipe(pn, d): | |||
341 | "from working. You will need to disable this " | 341 | "from working. You will need to disable this " |
342 | "first." % pn) | 342 | "first." % pn) |
343 | 343 | ||
344 | def _move_file(src, dst): | 344 | def _dry_run_copy(src, dst, dry_run_outdir, base_outdir): |
345 | """Move a file. Creates all the directory components of destination path.""" | 345 | """Common function for copying a file to the dry run output directory""" |
346 | relpath = os.path.relpath(dst, base_outdir) | ||
347 | if relpath.startswith('..'): | ||
348 | raise Exception('Incorrect base path %s for path %s' % (base_outdir, dst)) | ||
349 | dst = os.path.join(dry_run_outdir, relpath) | ||
346 | dst_d = os.path.dirname(dst) | 350 | dst_d = os.path.dirname(dst) |
347 | if dst_d: | 351 | if dst_d: |
348 | bb.utils.mkdirhier(dst_d) | 352 | bb.utils.mkdirhier(dst_d) |
349 | shutil.move(src, dst) | 353 | # Don't overwrite existing files, otherwise in the case of an upgrade |
354 | # the dry-run written out recipe will be overwritten with an unmodified | ||
355 | # version | ||
356 | if not os.path.exists(dst): | ||
357 | shutil.copy(src, dst) | ||
358 | |||
359 | def _move_file(src, dst, dry_run_outdir=None, base_outdir=None): | ||
360 | """Move a file. Creates all the directory components of destination path.""" | ||
361 | dry_run_suffix = ' (dry-run)' if dry_run_outdir else '' | ||
362 | logger.debug('Moving %s to %s%s' % (src, dst, dry_run_suffix)) | ||
363 | if dry_run_outdir: | ||
364 | # We want to copy here, not move | ||
365 | _dry_run_copy(src, dst, dry_run_outdir, base_outdir) | ||
366 | else: | ||
367 | dst_d = os.path.dirname(dst) | ||
368 | if dst_d: | ||
369 | bb.utils.mkdirhier(dst_d) | ||
370 | shutil.move(src, dst) | ||
350 | 371 | ||
351 | def _copy_file(src, dst): | 372 | def _copy_file(src, dst, dry_run_outdir=None): |
352 | """Copy a file. Creates all the directory components of destination path.""" | 373 | """Copy a file. Creates all the directory components of destination path.""" |
353 | dst_d = os.path.dirname(dst) | 374 | dry_run_suffix = ' (dry-run)' if dry_run_outdir else '' |
354 | if dst_d: | 375 | logger.debug('Copying %s to %s%s' % (src, dst, dry_run_suffix)) |
355 | bb.utils.mkdirhier(dst_d) | 376 | if dry_run_outdir: |
356 | shutil.copy(src, dst) | 377 | _dry_run_copy(src, dst, dry_run_outdir, base_outdir) |
378 | else: | ||
379 | dst_d = os.path.dirname(dst) | ||
380 | if dst_d: | ||
381 | bb.utils.mkdirhier(dst_d) | ||
382 | shutil.copy(src, dst) | ||
357 | 383 | ||
358 | def _git_ls_tree(repodir, treeish='HEAD', recursive=False): | 384 | def _git_ls_tree(repodir, treeish='HEAD', recursive=False): |
359 | """List contents of a git treeish""" | 385 | """List contents of a git treeish""" |
@@ -1054,8 +1080,11 @@ def _replace_srcuri_entry(srcuri, filename, newentry): | |||
1054 | srcuri.insert(i, newentry) | 1080 | srcuri.insert(i, newentry) |
1055 | break | 1081 | break |
1056 | 1082 | ||
1057 | def _remove_source_files(append, files, destpath, no_report_remove=False): | 1083 | def _remove_source_files(append, files, destpath, no_report_remove=False, dry_run=False): |
1058 | """Unlink existing patch files""" | 1084 | """Unlink existing patch files""" |
1085 | |||
1086 | dry_run_suffix = ' (dry-run)' if dry_run else '' | ||
1087 | |||
1059 | for path in files: | 1088 | for path in files: |
1060 | if append: | 1089 | if append: |
1061 | if not destpath: | 1090 | if not destpath: |
@@ -1064,19 +1093,20 @@ def _remove_source_files(append, files, destpath, no_report_remove=False): | |||
1064 | 1093 | ||
1065 | if os.path.exists(path): | 1094 | if os.path.exists(path): |
1066 | if not no_report_remove: | 1095 | if not no_report_remove: |
1067 | logger.info('Removing file %s' % path) | 1096 | logger.info('Removing file %s%s' % (path, dry_run_suffix)) |
1068 | # FIXME "git rm" here would be nice if the file in question is | 1097 | if not dry_run: |
1069 | # tracked | 1098 | # FIXME "git rm" here would be nice if the file in question is |
1070 | # FIXME there's a chance that this file is referred to by | 1099 | # tracked |
1071 | # another recipe, in which case deleting wouldn't be the | 1100 | # FIXME there's a chance that this file is referred to by |
1072 | # right thing to do | 1101 | # another recipe, in which case deleting wouldn't be the |
1073 | os.remove(path) | 1102 | # right thing to do |
1074 | # Remove directory if empty | 1103 | os.remove(path) |
1075 | try: | 1104 | # Remove directory if empty |
1076 | os.rmdir(os.path.dirname(path)) | 1105 | try: |
1077 | except OSError as ose: | 1106 | os.rmdir(os.path.dirname(path)) |
1078 | if ose.errno != errno.ENOTEMPTY: | 1107 | except OSError as ose: |
1079 | raise | 1108 | if ose.errno != errno.ENOTEMPTY: |
1109 | raise | ||
1080 | 1110 | ||
1081 | 1111 | ||
1082 | def _export_patches(srctree, rd, start_rev, destdir, changed_revs=None): | 1112 | def _export_patches(srctree, rd, start_rev, destdir, changed_revs=None): |
@@ -1277,13 +1307,16 @@ def _determine_files_dir(rd): | |||
1277 | return os.path.join(recipedir, rd.getVar('BPN')) | 1307 | return os.path.join(recipedir, rd.getVar('BPN')) |
1278 | 1308 | ||
1279 | 1309 | ||
1280 | def _update_recipe_srcrev(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove): | 1310 | def _update_recipe_srcrev(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove, dry_run_outdir=None): |
1281 | """Implement the 'srcrev' mode of update-recipe""" | 1311 | """Implement the 'srcrev' mode of update-recipe""" |
1282 | import bb | 1312 | import bb |
1283 | import oe.recipeutils | 1313 | import oe.recipeutils |
1284 | 1314 | ||
1315 | dry_run_suffix = ' (dry-run)' if dry_run_outdir else '' | ||
1316 | |||
1285 | recipefile = rd.getVar('FILE') | 1317 | recipefile = rd.getVar('FILE') |
1286 | logger.info('Updating SRCREV in recipe %s' % os.path.basename(recipefile)) | 1318 | recipedir = os.path.basename(recipefile) |
1319 | logger.info('Updating SRCREV in recipe %s%s' % (recipedir, dry_run_suffix)) | ||
1287 | 1320 | ||
1288 | # Get HEAD revision | 1321 | # Get HEAD revision |
1289 | try: | 1322 | try: |
@@ -1303,6 +1336,7 @@ def _update_recipe_srcrev(recipename, workspace, srctree, rd, appendlayerdir, wi | |||
1303 | srcuri = orig_src_uri.split() | 1336 | srcuri = orig_src_uri.split() |
1304 | tempdir = tempfile.mkdtemp(prefix='devtool') | 1337 | tempdir = tempfile.mkdtemp(prefix='devtool') |
1305 | update_srcuri = False | 1338 | update_srcuri = False |
1339 | appendfile = None | ||
1306 | try: | 1340 | try: |
1307 | local_files_dir = tempfile.mkdtemp(dir=tempdir) | 1341 | local_files_dir = tempfile.mkdtemp(dir=tempdir) |
1308 | srctreebase = workspace[recipename]['srctreebase'] | 1342 | srctreebase = workspace[recipename]['srctreebase'] |
@@ -1328,29 +1362,36 @@ def _update_recipe_srcrev(recipename, workspace, srctree, rd, appendlayerdir, wi | |||
1328 | if update_srcuri: | 1362 | if update_srcuri: |
1329 | removevalues = {'SRC_URI': removedentries} | 1363 | removevalues = {'SRC_URI': removedentries} |
1330 | patchfields['SRC_URI'] = '\\\n '.join(srcuri) | 1364 | patchfields['SRC_URI'] = '\\\n '.join(srcuri) |
1331 | _, destpath = oe.recipeutils.bbappend_recipe( | 1365 | if dry_run_outdir: |
1332 | rd, appendlayerdir, files, wildcardver=wildcard_version, | 1366 | logger.info('Creating bbappend (dry-run)') |
1333 | extralines=patchfields, removevalues=removevalues) | 1367 | else: |
1368 | appendfile, destpath = oe.recipeutils.bbappend_recipe( | ||
1369 | rd, appendlayerdir, files, wildcardver=wildcard_version, | ||
1370 | extralines=patchfields, removevalues=removevalues, | ||
1371 | redirect_output=dry_run_outdir) | ||
1334 | else: | 1372 | else: |
1335 | files_dir = _determine_files_dir(rd) | 1373 | files_dir = _determine_files_dir(rd) |
1336 | for basepath, path in upd_f.items(): | 1374 | for basepath, path in upd_f.items(): |
1337 | logger.info('Updating file %s' % basepath) | 1375 | logger.info('Updating file %s%s' % (basepath, dry_run_suffix)) |
1338 | if os.path.isabs(basepath): | 1376 | if os.path.isabs(basepath): |
1339 | # Original file (probably with subdir pointing inside source tree) | 1377 | # Original file (probably with subdir pointing inside source tree) |
1340 | # so we do not want to move it, just copy | 1378 | # so we do not want to move it, just copy |
1341 | _copy_file(basepath, path) | 1379 | _copy_file(basepath, path, dry_run_outdir=dry_run_outdir, base_outdir=recipedir) |
1342 | else: | 1380 | else: |
1343 | _move_file(os.path.join(local_files_dir, basepath), path) | 1381 | _move_file(os.path.join(local_files_dir, basepath), path, |
1382 | dry_run_outdir=dry_run_outdir, base_outdir=recipedir) | ||
1344 | update_srcuri= True | 1383 | update_srcuri= True |
1345 | for basepath, path in new_f.items(): | 1384 | for basepath, path in new_f.items(): |
1346 | logger.info('Adding new file %s' % basepath) | 1385 | logger.info('Adding new file %s%s' % (basepath, dry_run_suffix)) |
1347 | _move_file(os.path.join(local_files_dir, basepath), | 1386 | _move_file(os.path.join(local_files_dir, basepath), |
1348 | os.path.join(files_dir, basepath)) | 1387 | os.path.join(files_dir, basepath), |
1388 | dry_run_outdir=dry_run_outdir, | ||
1389 | base_outdir=recipedir) | ||
1349 | srcuri.append('file://%s' % basepath) | 1390 | srcuri.append('file://%s' % basepath) |
1350 | update_srcuri = True | 1391 | update_srcuri = True |
1351 | if update_srcuri: | 1392 | if update_srcuri: |
1352 | patchfields['SRC_URI'] = ' '.join(srcuri) | 1393 | patchfields['SRC_URI'] = ' '.join(srcuri) |
1353 | oe.recipeutils.patch_recipe(rd, recipefile, patchfields) | 1394 | ret = oe.recipeutils.patch_recipe(rd, recipefile, patchfields, redirect_output=dry_run_outdir) |
1354 | finally: | 1395 | finally: |
1355 | shutil.rmtree(tempdir) | 1396 | shutil.rmtree(tempdir) |
1356 | if not 'git://' in orig_src_uri: | 1397 | if not 'git://' in orig_src_uri: |
@@ -1358,15 +1399,16 @@ def _update_recipe_srcrev(recipename, workspace, srctree, rd, appendlayerdir, wi | |||
1358 | 'point to a git repository where you have pushed your ' | 1399 | 'point to a git repository where you have pushed your ' |
1359 | 'changes') | 1400 | 'changes') |
1360 | 1401 | ||
1361 | _remove_source_files(appendlayerdir, remove_files, destpath, no_report_remove) | 1402 | _remove_source_files(appendlayerdir, remove_files, destpath, no_report_remove, dry_run=dry_run_outdir) |
1362 | return True | 1403 | return True, appendfile, remove_files |
1363 | 1404 | ||
1364 | def _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove, initial_rev): | 1405 | def _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove, initial_rev, dry_run_outdir=None): |
1365 | """Implement the 'patch' mode of update-recipe""" | 1406 | """Implement the 'patch' mode of update-recipe""" |
1366 | import bb | 1407 | import bb |
1367 | import oe.recipeutils | 1408 | import oe.recipeutils |
1368 | 1409 | ||
1369 | recipefile = rd.getVar('FILE') | 1410 | recipefile = rd.getVar('FILE') |
1411 | recipedir = os.path.dirname(recipefile) | ||
1370 | append = workspace[recipename]['bbappend'] | 1412 | append = workspace[recipename]['bbappend'] |
1371 | if not os.path.exists(append): | 1413 | if not os.path.exists(append): |
1372 | raise DevtoolError('unable to find workspace bbappend for recipe %s' % | 1414 | raise DevtoolError('unable to find workspace bbappend for recipe %s' % |
@@ -1377,10 +1419,13 @@ def _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wil | |||
1377 | raise DevtoolError('Unable to find initial revision - please specify ' | 1419 | raise DevtoolError('Unable to find initial revision - please specify ' |
1378 | 'it with --initial-rev') | 1420 | 'it with --initial-rev') |
1379 | 1421 | ||
1422 | appendfile = None | ||
1380 | dl_dir = rd.getVar('DL_DIR') | 1423 | dl_dir = rd.getVar('DL_DIR') |
1381 | if not dl_dir.endswith('/'): | 1424 | if not dl_dir.endswith('/'): |
1382 | dl_dir += '/' | 1425 | dl_dir += '/' |
1383 | 1426 | ||
1427 | dry_run_suffix = ' (dry-run)' if dry_run_outdir else '' | ||
1428 | |||
1384 | tempdir = tempfile.mkdtemp(prefix='devtool') | 1429 | tempdir = tempfile.mkdtemp(prefix='devtool') |
1385 | try: | 1430 | try: |
1386 | local_files_dir = tempfile.mkdtemp(dir=tempdir) | 1431 | local_files_dir = tempfile.mkdtemp(dir=tempdir) |
@@ -1418,10 +1463,11 @@ def _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wil | |||
1418 | remaining = ['file://' + os.path.basename(item) for | 1463 | remaining = ['file://' + os.path.basename(item) for |
1419 | item in remaining] | 1464 | item in remaining] |
1420 | removevalues = {'SRC_URI': removedentries + remaining} | 1465 | removevalues = {'SRC_URI': removedentries + remaining} |
1421 | _, destpath = oe.recipeutils.bbappend_recipe( | 1466 | appendfile, destpath = oe.recipeutils.bbappend_recipe( |
1422 | rd, appendlayerdir, files, | 1467 | rd, appendlayerdir, files, |
1423 | wildcardver=wildcard_version, | 1468 | wildcardver=wildcard_version, |
1424 | removevalues=removevalues) | 1469 | removevalues=removevalues, |
1470 | redirect_output=dry_run_outdir) | ||
1425 | else: | 1471 | else: |
1426 | logger.info('No patches or local source files needed updating') | 1472 | logger.info('No patches or local source files needed updating') |
1427 | else: | 1473 | else: |
@@ -1432,9 +1478,11 @@ def _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wil | |||
1432 | if os.path.isabs(basepath): | 1478 | if os.path.isabs(basepath): |
1433 | # Original file (probably with subdir pointing inside source tree) | 1479 | # Original file (probably with subdir pointing inside source tree) |
1434 | # so we do not want to move it, just copy | 1480 | # so we do not want to move it, just copy |
1435 | _copy_file(basepath, path) | 1481 | _copy_file(basepath, path, |
1482 | dry_run_outdir=dry_run_outdir, base_outdir=recipedir) | ||
1436 | else: | 1483 | else: |
1437 | _move_file(os.path.join(local_files_dir, basepath), path) | 1484 | _move_file(os.path.join(local_files_dir, basepath), path, |
1485 | dry_run_outdir=dry_run_outdir, base_outdir=recipedir) | ||
1438 | updatefiles = True | 1486 | updatefiles = True |
1439 | for basepath, path in upd_p.items(): | 1487 | for basepath, path in upd_p.items(): |
1440 | patchfn = os.path.join(patches_dir, basepath) | 1488 | patchfn = os.path.join(patches_dir, basepath) |
@@ -1446,39 +1494,45 @@ def _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wil | |||
1446 | _replace_srcuri_entry(srcuri, basepath, 'file://%s' % basepath) | 1494 | _replace_srcuri_entry(srcuri, basepath, 'file://%s' % basepath) |
1447 | updaterecipe = True | 1495 | updaterecipe = True |
1448 | else: | 1496 | else: |
1449 | logger.info('Updating patch %s' % basepath) | 1497 | logger.info('Updating patch %s%s' % (basepath, dry_run_suffix)) |
1450 | logger.debug('Moving new patch %s to %s' % (patchfn, path)) | 1498 | _move_file(patchfn, path, |
1451 | _move_file(patchfn, path) | 1499 | dry_run_outdir=dry_run_outdir, base_outdir=recipedir) |
1452 | updatefiles = True | 1500 | updatefiles = True |
1453 | # Add any new files | 1501 | # Add any new files |
1454 | for basepath, path in new_f.items(): | 1502 | for basepath, path in new_f.items(): |
1455 | logger.info('Adding new file %s' % basepath) | 1503 | logger.info('Adding new file %s%s' % (basepath, dry_run_suffix)) |
1456 | _move_file(os.path.join(local_files_dir, basepath), | 1504 | _move_file(os.path.join(local_files_dir, basepath), |
1457 | os.path.join(files_dir, basepath)) | 1505 | os.path.join(files_dir, basepath), |
1506 | dry_run_outdir=dry_run_outdir, | ||
1507 | base_outdir=recipedir) | ||
1458 | srcuri.append('file://%s' % basepath) | 1508 | srcuri.append('file://%s' % basepath) |
1459 | updaterecipe = True | 1509 | updaterecipe = True |
1460 | for basepath, path in new_p.items(): | 1510 | for basepath, path in new_p.items(): |
1461 | logger.info('Adding new patch %s' % basepath) | 1511 | logger.info('Adding new patch %s%s' % (basepath, dry_run_suffix)) |
1462 | _move_file(os.path.join(patches_dir, basepath), | 1512 | _move_file(os.path.join(patches_dir, basepath), |
1463 | os.path.join(files_dir, basepath)) | 1513 | os.path.join(files_dir, basepath), |
1514 | dry_run_outdir=dry_run_outdir, | ||
1515 | base_outdir=recipedir) | ||
1464 | srcuri.append('file://%s' % basepath) | 1516 | srcuri.append('file://%s' % basepath) |
1465 | updaterecipe = True | 1517 | updaterecipe = True |
1466 | # Update recipe, if needed | 1518 | # Update recipe, if needed |
1467 | if _remove_file_entries(srcuri, remove_files)[0]: | 1519 | if _remove_file_entries(srcuri, remove_files)[0]: |
1468 | updaterecipe = True | 1520 | updaterecipe = True |
1469 | if updaterecipe: | 1521 | if updaterecipe: |
1470 | logger.info('Updating recipe %s' % os.path.basename(recipefile)) | 1522 | if not dry_run_outdir: |
1471 | oe.recipeutils.patch_recipe(rd, recipefile, | 1523 | logger.info('Updating recipe %s' % os.path.basename(recipefile)) |
1472 | {'SRC_URI': ' '.join(srcuri)}) | 1524 | ret = oe.recipeutils.patch_recipe(rd, recipefile, |
1525 | {'SRC_URI': ' '.join(srcuri)}, | ||
1526 | redirect_output=dry_run_outdir) | ||
1473 | elif not updatefiles: | 1527 | elif not updatefiles: |
1474 | # Neither patches nor recipe were updated | 1528 | # Neither patches nor recipe were updated |
1475 | logger.info('No patches or files need updating') | 1529 | logger.info('No patches or files need updating') |
1476 | return False | 1530 | return False, None, [] |
1477 | finally: | 1531 | finally: |
1478 | shutil.rmtree(tempdir) | 1532 | shutil.rmtree(tempdir) |
1479 | 1533 | ||
1480 | _remove_source_files(appendlayerdir, remove_files, destpath, no_report_remove) | 1534 | _remove_source_files(appendlayerdir, remove_files, destpath, no_report_remove, dry_run=dry_run_outdir) |
1481 | return True | 1535 | return True, appendfile, remove_files |
1482 | 1536 | ||
1483 | def _guess_recipe_update_mode(srctree, rdata): | 1537 | def _guess_recipe_update_mode(srctree, rdata): |
1484 | """Guess the recipe update mode to use""" | 1538 | """Guess the recipe update mode to use""" |
@@ -1502,18 +1556,18 @@ def _guess_recipe_update_mode(srctree, rdata): | |||
1502 | 1556 | ||
1503 | return 'patch' | 1557 | return 'patch' |
1504 | 1558 | ||
1505 | def _update_recipe(recipename, workspace, rd, mode, appendlayerdir, wildcard_version, no_remove, initial_rev, no_report_remove=False): | 1559 | def _update_recipe(recipename, workspace, rd, mode, appendlayerdir, wildcard_version, no_remove, initial_rev, no_report_remove=False, dry_run_outdir=None): |
1506 | srctree = workspace[recipename]['srctree'] | 1560 | srctree = workspace[recipename]['srctree'] |
1507 | if mode == 'auto': | 1561 | if mode == 'auto': |
1508 | mode = _guess_recipe_update_mode(srctree, rd) | 1562 | mode = _guess_recipe_update_mode(srctree, rd) |
1509 | 1563 | ||
1510 | if mode == 'srcrev': | 1564 | if mode == 'srcrev': |
1511 | updated = _update_recipe_srcrev(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove) | 1565 | updated, appendfile, removed = _update_recipe_srcrev(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove, dry_run_outdir) |
1512 | elif mode == 'patch': | 1566 | elif mode == 'patch': |
1513 | updated = _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove, initial_rev) | 1567 | updated, appendfile, removed = _update_recipe_patch(recipename, workspace, srctree, rd, appendlayerdir, wildcard_version, no_remove, no_report_remove, initial_rev, dry_run_outdir) |
1514 | else: | 1568 | else: |
1515 | raise DevtoolError('update_recipe: invalid mode %s' % mode) | 1569 | raise DevtoolError('update_recipe: invalid mode %s' % mode) |
1516 | return updated | 1570 | return updated, appendfile, removed |
1517 | 1571 | ||
1518 | def update_recipe(args, config, basepath, workspace): | 1572 | def update_recipe(args, config, basepath, workspace): |
1519 | """Entry point for the devtool 'update-recipe' subcommand""" | 1573 | """Entry point for the devtool 'update-recipe' subcommand""" |
@@ -1534,7 +1588,12 @@ def update_recipe(args, config, basepath, workspace): | |||
1534 | if not rd: | 1588 | if not rd: |
1535 | return 1 | 1589 | return 1 |
1536 | 1590 | ||
1537 | updated = _update_recipe(args.recipename, workspace, rd, args.mode, args.append, args.wildcard_version, args.no_remove, args.initial_rev) | 1591 | dry_run_output = None |
1592 | dry_run_outdir = None | ||
1593 | if args.dry_run: | ||
1594 | dry_run_output = tempfile.TemporaryDirectory(prefix='devtool') | ||
1595 | dry_run_outdir = dry_run_output.name | ||
1596 | updated, _, _ = _update_recipe(args.recipename, workspace, rd, args.mode, args.append, args.wildcard_version, args.no_remove, args.initial_rev, dry_run_outdir=dry_run_outdir) | ||
1538 | 1597 | ||
1539 | if updated: | 1598 | if updated: |
1540 | rf = rd.getVar('FILE') | 1599 | rf = rd.getVar('FILE') |
@@ -1680,6 +1739,8 @@ def finish(args, config, basepath, workspace): | |||
1680 | 1739 | ||
1681 | check_workspace_recipe(workspace, args.recipename) | 1740 | check_workspace_recipe(workspace, args.recipename) |
1682 | 1741 | ||
1742 | dry_run_suffix = ' (dry-run)' if args.dry_run else '' | ||
1743 | |||
1683 | # Grab the equivalent of COREBASE without having to initialise tinfoil | 1744 | # Grab the equivalent of COREBASE without having to initialise tinfoil |
1684 | corebasedir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) | 1745 | corebasedir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) |
1685 | 1746 | ||
@@ -1700,7 +1761,9 @@ def finish(args, config, basepath, workspace): | |||
1700 | return 1 | 1761 | return 1 |
1701 | 1762 | ||
1702 | destlayerdir = _get_layer(args.destination, tinfoil.config_data) | 1763 | destlayerdir = _get_layer(args.destination, tinfoil.config_data) |
1703 | origlayerdir = oe.recipeutils.find_layerdir(rd.getVar('FILE')) | 1764 | recipefile = rd.getVar('FILE') |
1765 | recipedir = os.path.dirname(recipefile) | ||
1766 | origlayerdir = oe.recipeutils.find_layerdir(recipefile) | ||
1704 | 1767 | ||
1705 | if not os.path.isdir(destlayerdir): | 1768 | if not os.path.isdir(destlayerdir): |
1706 | raise DevtoolError('Unable to find layer or directory matching "%s"' % args.destination) | 1769 | raise DevtoolError('Unable to find layer or directory matching "%s"' % args.destination) |
@@ -1748,38 +1811,101 @@ def finish(args, config, basepath, workspace): | |||
1748 | 1811 | ||
1749 | # Actually update the recipe / bbappend | 1812 | # Actually update the recipe / bbappend |
1750 | removing_original = (origpath and origfilelist and oe.recipeutils.find_layerdir(origpath) == destlayerbasedir) | 1813 | removing_original = (origpath and origfilelist and oe.recipeutils.find_layerdir(origpath) == destlayerbasedir) |
1751 | _update_recipe(args.recipename, workspace, rd, args.mode, appendlayerdir, wildcard_version=True, no_remove=False, initial_rev=args.initial_rev, no_report_remove=removing_original) | 1814 | dry_run_output = None |
1815 | dry_run_outdir = None | ||
1816 | if args.dry_run: | ||
1817 | dry_run_output = tempfile.TemporaryDirectory(prefix='devtool') | ||
1818 | dry_run_outdir = dry_run_output.name | ||
1819 | updated, appendfile, removed = _update_recipe(args.recipename, workspace, rd, args.mode, appendlayerdir, wildcard_version=True, no_remove=False, no_report_remove=removing_original, initial_rev=args.initial_rev, dry_run_outdir=dry_run_outdir) | ||
1820 | removed = [os.path.relpath(pth, recipedir) for pth in removed] | ||
1752 | 1821 | ||
1753 | # Remove any old files in the case of an upgrade | 1822 | # Remove any old files in the case of an upgrade |
1754 | recipedir = os.path.dirname(rd.getVar('FILE')) | ||
1755 | if removing_original: | 1823 | if removing_original: |
1756 | for fn in origfilelist: | 1824 | for fn in origfilelist: |
1757 | fnp = os.path.join(origpath, fn) | 1825 | fnp = os.path.join(origpath, fn) |
1758 | if not os.path.exists(os.path.join(recipedir, fn)): | 1826 | if fn in removed or not os.path.exists(os.path.join(recipedir, fn)): |
1759 | logger.info('Removing file %s' % fnp) | 1827 | logger.info('Removing file %s%s' % (fnp, dry_run_suffix)) |
1760 | try: | 1828 | if not args.dry_run: |
1761 | os.remove(fnp) | 1829 | try: |
1762 | except FileNotFoundError: | 1830 | os.remove(fnp) |
1763 | pass | 1831 | except FileNotFoundError: |
1832 | pass | ||
1764 | 1833 | ||
1765 | if origlayerdir == config.workspace_path and destpath: | 1834 | if origlayerdir == config.workspace_path and destpath: |
1766 | # Recipe file itself is in the workspace - need to move it and any | 1835 | # Recipe file itself is in the workspace - need to move it and any |
1767 | # associated files to the specified layer | 1836 | # associated files to the specified layer |
1768 | no_clean = True | 1837 | no_clean = True |
1769 | logger.info('Moving recipe file to %s' % destpath) | 1838 | logger.info('Moving recipe file to %s%s' % (destpath, dry_run_suffix)) |
1770 | for root, _, files in os.walk(recipedir): | 1839 | for root, _, files in os.walk(recipedir): |
1771 | for fn in files: | 1840 | for fn in files: |
1772 | srcpath = os.path.join(root, fn) | 1841 | srcpath = os.path.join(root, fn) |
1773 | relpth = os.path.relpath(os.path.dirname(srcpath), recipedir) | 1842 | relpth = os.path.relpath(os.path.dirname(srcpath), recipedir) |
1774 | destdir = os.path.abspath(os.path.join(destpath, relpth)) | 1843 | destdir = os.path.abspath(os.path.join(destpath, relpth)) |
1775 | bb.utils.mkdirhier(destdir) | 1844 | destfp = os.path.join(destdir, fn) |
1776 | shutil.move(srcpath, os.path.join(destdir, fn)) | 1845 | _move_file(srcpath, destfp, dry_run_outdir=dry_run_outdir, base_outdir=destpath) |
1777 | 1846 | ||
1847 | if dry_run_outdir: | ||
1848 | import difflib | ||
1849 | comparelist = [] | ||
1850 | for root, _, files in os.walk(dry_run_outdir): | ||
1851 | for fn in files: | ||
1852 | outf = os.path.join(root, fn) | ||
1853 | relf = os.path.relpath(outf, dry_run_outdir) | ||
1854 | logger.debug('dry-run: output file %s' % relf) | ||
1855 | if fn.endswith('.bb'): | ||
1856 | if origfilelist and origpath and destpath: | ||
1857 | # Need to match this up with the pre-upgrade recipe file | ||
1858 | for origf in origfilelist: | ||
1859 | if origf.endswith('.bb'): | ||
1860 | comparelist.append((os.path.abspath(os.path.join(origpath, origf)), | ||
1861 | outf, | ||
1862 | os.path.abspath(os.path.join(destpath, relf)))) | ||
1863 | break | ||
1864 | else: | ||
1865 | # Compare to the existing recipe | ||
1866 | comparelist.append((recipefile, outf, recipefile)) | ||
1867 | elif fn.endswith('.bbappend'): | ||
1868 | if appendfile: | ||
1869 | if os.path.exists(appendfile): | ||
1870 | comparelist.append((appendfile, outf, appendfile)) | ||
1871 | else: | ||
1872 | comparelist.append((None, outf, appendfile)) | ||
1873 | else: | ||
1874 | if destpath: | ||
1875 | recipedest = destpath | ||
1876 | elif appendfile: | ||
1877 | recipedest = os.path.dirname(appendfile) | ||
1878 | else: | ||
1879 | recipedest = os.path.dirname(recipefile) | ||
1880 | destfp = os.path.join(recipedest, relf) | ||
1881 | if os.path.exists(destfp): | ||
1882 | comparelist.append((destfp, outf, destfp)) | ||
1883 | output = '' | ||
1884 | for oldfile, newfile, newfileshow in comparelist: | ||
1885 | if oldfile: | ||
1886 | with open(oldfile, 'r') as f: | ||
1887 | oldlines = f.readlines() | ||
1888 | else: | ||
1889 | oldfile = '/dev/null' | ||
1890 | oldlines = [] | ||
1891 | with open(newfile, 'r') as f: | ||
1892 | newlines = f.readlines() | ||
1893 | if not newfileshow: | ||
1894 | newfileshow = newfile | ||
1895 | diff = difflib.unified_diff(oldlines, newlines, oldfile, newfileshow) | ||
1896 | difflines = list(diff) | ||
1897 | if difflines: | ||
1898 | output += ''.join(difflines) | ||
1899 | if output: | ||
1900 | logger.info('Diff of changed files:\n%s' % output) | ||
1778 | finally: | 1901 | finally: |
1779 | tinfoil.shutdown() | 1902 | tinfoil.shutdown() |
1780 | 1903 | ||
1781 | # Everything else has succeeded, we can now reset | 1904 | # Everything else has succeeded, we can now reset |
1782 | _reset([args.recipename], no_clean=no_clean, config=config, basepath=basepath, workspace=workspace) | 1905 | if args.dry_run: |
1906 | logger.info('Resetting recipe (dry-run)') | ||
1907 | else: | ||
1908 | _reset([args.recipename], no_clean=no_clean, config=config, basepath=basepath, workspace=workspace) | ||
1783 | 1909 | ||
1784 | return 0 | 1910 | return 0 |
1785 | 1911 | ||
@@ -1873,6 +1999,7 @@ def register_commands(subparsers, context): | |||
1873 | parser_update_recipe.add_argument('--append', '-a', help='Write changes to a bbappend in the specified layer instead of the recipe', metavar='LAYERDIR') | 1999 | parser_update_recipe.add_argument('--append', '-a', help='Write changes to a bbappend in the specified layer instead of the recipe', metavar='LAYERDIR') |
1874 | parser_update_recipe.add_argument('--wildcard-version', '-w', help='In conjunction with -a/--append, use a wildcard to make the bbappend apply to any recipe version', action='store_true') | 2000 | parser_update_recipe.add_argument('--wildcard-version', '-w', help='In conjunction with -a/--append, use a wildcard to make the bbappend apply to any recipe version', action='store_true') |
1875 | parser_update_recipe.add_argument('--no-remove', '-n', action="store_true", help='Don\'t remove patches, only add or update') | 2001 | parser_update_recipe.add_argument('--no-remove', '-n', action="store_true", help='Don\'t remove patches, only add or update') |
2002 | parser_update_recipe.add_argument('--dry-run', '-N', action="store_true", help='Dry-run (just report changes instead of writing them)') | ||
1876 | parser_update_recipe.set_defaults(func=update_recipe) | 2003 | parser_update_recipe.set_defaults(func=update_recipe) |
1877 | 2004 | ||
1878 | parser_status = subparsers.add_parser('status', help='Show workspace status', | 2005 | parser_status = subparsers.add_parser('status', help='Show workspace status', |
@@ -1896,4 +2023,5 @@ def register_commands(subparsers, context): | |||
1896 | 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') | 2023 | 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') |
1897 | parser_finish.add_argument('--initial-rev', help='Override starting revision for patches') | 2024 | parser_finish.add_argument('--initial-rev', help='Override starting revision for patches') |
1898 | parser_finish.add_argument('--force', '-f', action="store_true", help='Force continuing even if there are uncommitted changes in the source tree repository') | 2025 | parser_finish.add_argument('--force', '-f', action="store_true", help='Force continuing even if there are uncommitted changes in the source tree repository') |
2026 | parser_finish.add_argument('--dry-run', '-N', action="store_true", help='Dry-run (just report changes instead of writing them)') | ||
1899 | parser_finish.set_defaults(func=finish) | 2027 | parser_finish.set_defaults(func=finish) |