@@ -166,7 +166,7 @@ def _get_remotes(r_remote):
return remotes
-def checkout_layers(layers, confdir, layerdir, d):
+def checkout_layers(layers, confdir, layerdir, d, rebase_strategy='stop'):
def _checkout_git_remote(r_remote, repodir, layers_fixed_revisions):
rev = r_remote['rev']
branch = r_remote.get('branch', None)
@@ -186,10 +186,20 @@ def checkout_layers(layers, confdir, layerdir, d):
try:
do_fetch(fetcher, layerdir)
except bb.fetch2.UnpackError as e:
- raise Exception(
- "Cannot update source '{}' in {} because it has local modifications.\n"
- "Please commit, stash or discard your changes and re-run the update.\n"
- "Details: {}".format(r_name, repodir_path, e)) from None
+ if rebase_strategy == 'backup':
+ backup_path = add_unique_timestamp_to_path(repodir_path + '-backup')
+ logger.warning(
+ "Source '{}' at {} has local modifications that prevent an in-place update.\n"
+ "Renaming it to {} to preserve your work, then re-cloning from upstream."
+ .format(r_name, repodir_path, backup_path))
+ os.rename(repodir_path, backup_path)
+ fetcher.unpack(layerdir)
+ else:
+ raise Exception(
+ "Cannot update source '{}' in {} because it has local modifications.\n"
+ "Please commit, stash or discard your changes and re-run the update,\n"
+ "or use --rebase-strategy=backup to back up the directory and re-clone automatically.\n"
+ "Details: {}".format(r_name, repodir_path, e)) from None
urldata = fetcher.ud[src_uri]
revision = urldata.revision
layers_fixed_revisions[r_name]['git-remote']['rev'] = revision
@@ -444,9 +454,9 @@ def merge_overrides_into_sources(sources, overrides):
layers[k] = v
return layers
-def update_build(config, confdir, setupdir, layerdir, d, update_bb_conf="prompt", init_vscode=False):
+def update_build(config, confdir, setupdir, layerdir, d, update_bb_conf="prompt", init_vscode=False, rebase_strategy='stop'):
layer_config = merge_overrides_into_sources(config["data"]["sources"], config["source-overrides"]["sources"])
- sources_fixed_revisions = checkout_layers(layer_config, confdir, layerdir, d)
+ sources_fixed_revisions = checkout_layers(layer_config, confdir, layerdir, d, rebase_strategy=rebase_strategy)
bitbake_config = config["bitbake-config"]
thisdir = os.path.dirname(config["path"]) if config["type"] == 'local' else None
bitbake_builddir, init_script = setup_bitbake_build(bitbake_config, layerdir, setupdir, thisdir, update_bb_conf, init_vscode)
@@ -933,7 +943,7 @@ def build_status(top_dir, settings, args, d, update=False):
logger.plain('\nConfiguration in {} has changed:\n{}'.format(setupdir, config_diff))
if update:
bitbake_builddir, init_script = update_build(new_upstream_config, confdir, setupdir, layerdir, d,
- update_bb_conf=args.update_bb_conf, init_vscode=args.init_vscode)
+ update_bb_conf=args.update_bb_conf, init_vscode=args.init_vscode, rebase_strategy=args.rebase_strategy)
if args.init_vscode:
configure_vscode(setupdir, layerdir, bitbake_builddir, init_script)
else:
@@ -944,7 +954,7 @@ def build_status(top_dir, settings, args, d, update=False):
if are_layers_changed(layer_config, layerdir, d):
if update:
bitbake_builddir, init_script = update_build(current_upstream_config, confdir, setupdir, layerdir,
- d, update_bb_conf=args.update_bb_conf, init_vscode=args.init_vscode)
+ d, update_bb_conf=args.update_bb_conf, init_vscode=args.init_vscode, rebase_strategy=args.rebase_strategy)
if args.init_vscode:
configure_vscode(setupdir, layerdir, bitbake_builddir, init_script)
return
@@ -1272,6 +1282,10 @@ def main():
parser_update.add_argument('--update-bb-conf', choices=['prompt', 'yes', 'no'], default='prompt', help='Update bitbake configuration files (bblayers.conf, local.conf) (default: prompt)')
parser_update.add_argument('--init-vscode', action=argparse.BooleanOptionalAction, default=bool(shutil.which('code')),
help='Generate VSCode workspace configuration (default: %(default)s)')
+ parser_update.add_argument('--rebase-strategy', choices=['stop', 'backup'], default='stop',
+ help="What to do when a layer repository has local modifications that prevent "
+ "an in-place update: 'stop' (default) aborts with an error message; "
+ "'backup' renames the directory to a timestamped backup and re-clones from upstream.")
parser_update.set_defaults(func=build_update)
parser_install_buildtools = subparsers.add_parser('install-buildtools', help='Install buildtools which can help fulfil missing or incorrect dependencies on the host machine')