@@ -152,6 +152,27 @@ def add_unique_timestamp_to_path(path):
break
return path_unique
+def _filter_extra_remotes(extra_remotes, filter_value):
+ """
+ Filter the extra-remotes dict according to --extra-remotes-filter.
+ 'non-optional' -> return only entries where optional is False (default)
+ 'all' -> return all entries including optional ones
+ 'none' -> return empty dict
+ otherwise -> treat filter_value as a comma-separated list of allowed remote names
+ """
+ logger.debug("_filter_extra_remotes: filter='{}', candidates={}".format(filter_value, list(extra_remotes.keys())))
+ if filter_value == 'non-optional':
+ result = {k: v for k, v in extra_remotes.items() if not v.get('optional', False)}
+ elif filter_value == 'all':
+ result = extra_remotes
+ elif filter_value == 'none':
+ result = {}
+ else:
+ allowed = {n.strip() for n in filter_value.split(',')}
+ result = {k: v for k, v in extra_remotes.items() if k in allowed}
+ logger.debug("_filter_extra_remotes: selected={}".format(list(result.keys())))
+ return result
+
def _get_remotes(r_remote):
remotes = []
@@ -167,7 +188,41 @@ def _get_remotes(r_remote):
return remotes
-def checkout_layers(layers, confdir, layerdir, d, rebase_conflicts_strategy='abort'):
+def _add_extra_remotes(extra_remotes, repodir_path):
+ if not os.path.exists(os.path.join(repodir_path, '.git')):
+ logger.debug("_add_extra_remotes: skipping {}, no .git entry found".format(repodir_path))
+ return
+ existing = bb.process.run('git -C {} remote'.format(repodir_path))[0].split()
+ logger.debug("_add_extra_remotes: existing remotes in {}: {}".format(repodir_path, existing))
+ for remote_name, remote_data in extra_remotes.items():
+ uri = remote_data['uri']
+ try:
+ if remote_name in existing:
+ bb.process.run('git -C {} remote set-url {} {}'.format(repodir_path, remote_name, uri))
+ logger.plain(" Updated extra remote '{}' -> {}".format(remote_name, uri))
+ else:
+ bb.process.run('git -C {} remote add {} {}'.format(repodir_path, remote_name, uri))
+ logger.plain(" Added extra remote '{}' -> {}".format(remote_name, uri))
+ except bb.process.ExecutionError as e:
+ logger.warning(" Skipping extra remote '{}': {}".format(remote_name, e))
+
+def _apply_extra_remotes(r_name, r_data, layerdir, extra_remotes_filter):
+ r_remote = r_data.get('git-remote')
+ if not r_remote:
+ logger.debug("_apply_extra_remotes: skipping {}, no git-remote".format(r_name))
+ return
+ extra_remotes = r_remote.get('extra-remotes')
+ if not extra_remotes:
+ logger.debug("_apply_extra_remotes: skipping {}, no extra-remotes defined".format(r_name))
+ return
+ extra_remotes = _filter_extra_remotes(extra_remotes, extra_remotes_filter)
+ if extra_remotes:
+ repodir = r_data.get('path', r_name)
+ _add_extra_remotes(extra_remotes, os.path.join(layerdir, repodir))
+ else:
+ logger.debug("_apply_extra_remotes: all extra-remotes for {} were filtered out".format(r_name))
+
+def checkout_layers(layers, confdir, layerdir, d, rebase_conflicts_strategy='abort', extra_remotes_filter='non-optional'):
def _checkout_git_remote(r_remote, repodir, layers_fixed_revisions):
rev = r_remote['rev']
branch = r_remote.get('branch', None)
@@ -236,6 +291,7 @@ bitbake-setup init -L {} /path/to/repo/checkout""".format(
if r_remote:
_checkout_git_remote(r_remote, repodir, layers_fixed_revisions)
+ _apply_extra_remotes(r_name, r_data, layerdir, extra_remotes_filter)
if r_local:
_symlink_local(os.path.expanduser(r_local["path"]), repodir_path)
@@ -458,9 +514,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, rebase_conflicts_strategy='abort'):
+def update_build(config, confdir, setupdir, layerdir, d, update_bb_conf="prompt", init_vscode=False, rebase_conflicts_strategy='abort', extra_remotes_filter='non-optional'):
layer_config = merge_overrides_into_sources(config["data"]["sources"], config["source-overrides"]["sources"])
- sources_fixed_revisions = checkout_layers(layer_config, confdir, layerdir, d, rebase_conflicts_strategy=rebase_conflicts_strategy)
+ sources_fixed_revisions = checkout_layers(layer_config, confdir, layerdir, d, rebase_conflicts_strategy=rebase_conflicts_strategy, extra_remotes_filter=extra_remotes_filter)
bitbake_config = config["bitbake-config"]
thisdir = os.path.dirname(config["path"]) if config["type"] == 'local' else None
setup_bitbake_build(bitbake_config, layerdir, setupdir, thisdir, update_bb_conf, init_vscode)
@@ -866,7 +922,7 @@ def init_config(top_dir, settings, args):
bb.event.register("bb.build.TaskProgress", handle_task_progress, data=d)
write_upstream_config(confdir, upstream_config)
- update_build(upstream_config, confdir, setupdir, layerdir, d, update_bb_conf="yes", init_vscode=args.init_vscode)
+ update_build(upstream_config, confdir, setupdir, layerdir, d, update_bb_conf="yes", init_vscode=args.init_vscode, extra_remotes_filter=args.extra_remotes_filter)
bb.event.remove("bb.build.TaskProgress", None)
@@ -943,7 +999,8 @@ def build_status(top_dir, settings, args, d, update=False):
logger.plain('\nConfiguration in {} has changed:\n{}'.format(setupdir, config_diff))
if update:
update_build(new_upstream_config, confdir, setupdir, layerdir, d,
- update_bb_conf=args.update_bb_conf, rebase_conflicts_strategy=args.rebase_conflicts_strategy)
+ update_bb_conf=args.update_bb_conf, rebase_conflicts_strategy=args.rebase_conflicts_strategy,
+ extra_remotes_filter=args.extra_remotes_filter)
else:
bb.process.run('git -C {} restore config-upstream.json'.format(confdir))
return
@@ -952,11 +1009,14 @@ def build_status(top_dir, settings, args, d, update=False):
if are_layers_changed(layer_config, layerdir, d):
if update:
update_build(current_upstream_config, confdir, setupdir, layerdir,
- d, update_bb_conf=args.update_bb_conf, rebase_conflicts_strategy=args.rebase_conflicts_strategy)
+ d, update_bb_conf=args.update_bb_conf, rebase_conflicts_strategy=args.rebase_conflicts_strategy,
+ extra_remotes_filter=args.extra_remotes_filter)
return
logger.plain("\nConfiguration in {} has not changed.".format(setupdir))
if update:
+ for r_name, r_data in layer_config.items():
+ _apply_extra_remotes(r_name, r_data, layerdir, args.extra_remotes_filter)
workspace_file = os.path.join(setupdir, "bitbake.code-workspace")
if os.path.exists(workspace_file):
bitbake_builddir = os.path.join(setupdir, "build")
@@ -1239,6 +1299,14 @@ def main():
else:
parser.add_argument('--setup-dir', required=True, help="Path to the setup")
+ def add_extra_remotes_filter_arg(parser):
+ parser.add_argument('--extra-remotes-filter', default='non-optional', metavar='FILTER', dest='extra_remotes_filter',
+ help="Control which extra-remotes are configured in checked-out repositories: "
+ "'non-optional' (default) configures only extra-remotes that are not marked as optional; "
+ "'all' configures all extra-remotes including optional ones; "
+ "'none' skips all extra-remotes; "
+ "a comma-separated list of remote names configures only those named remotes (e.g. 'contrib,upstream').")
+
parser = argparse.ArgumentParser(
description="BitBake setup utility. Run with 'init' argument to get started.",
epilog="Use %(prog)s <subcommand> --help to get help on a specific command"
@@ -1269,6 +1337,7 @@ def main():
help='Symlink local source into a build, instead of getting it as prescribed by a configuration (useful for local development).')
parser_init.add_argument('--init-vscode', action=argparse.BooleanOptionalAction, default=bool(shutil.which('code')),
help='Generate VSCode workspace configuration (default: %(default)s)')
+ add_extra_remotes_filter_arg(parser_init)
parser_init.set_defaults(func=init_config)
parser_status = subparsers.add_parser('status', help='Check if the setup needs to be synchronized with configuration')
@@ -1282,6 +1351,7 @@ def main():
help="What to do when a layer repository has local modifications that prevent "
"an in-place update: 'abort' (default) aborts with an error message; "
"'backup' renames the directory to a timestamped backup and re-clones from upstream.")
+ add_extra_remotes_filter_arg(parser_update)
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')
@@ -67,6 +67,28 @@
}
}
}}
+ },
+ "extra-remotes": {
+ "description": "Additional named git remotes to configure in the checked-out repository. These are not used for fetching or change detection, only added via 'git remote add'.",
+ "type": "object",
+ "patternProperties": { ".*" : {
+ "description": "An extra git remote",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "uri"
+ ],
+ "properties": {
+ "uri": {
+ "description": "The URI for the remote",
+ "type": "string"
+ },
+ "optional": {
+ "description": "If true, the remote is excluded by the default 'non-optional' filter. Useful for remotes that require special access (e.g. contrib push URIs with SSH keys).",
+ "type": "boolean"
+ }
+ }
+ }}
}
}
},