@@ -18,6 +18,28 @@ import configparser
import datetime
import glob
import subprocess
+import re
+
+class JSONComment(json.JSONDecoder):
+ @staticmethod
+ def remove_comments(code: str) -> str:
+ # Remove // comments while preserving those inside strings
+ # This regex matches either quoted strings or // comments
+ pattern = re.compile(r'"(?:[^"\\]|\\.)*"|//.*?(?=\n|$)', re.MULTILINE)
+
+ def replacer(match):
+ # If the match starts with a quote, it's a string - keep it
+ if match.group(0).startswith('"'):
+ return match.group(0)
+ # Otherwise it's a comment - remove it
+ return ''
+
+ return pattern.sub(replacer, code)
+ def raw_decode(self, s, idx):
+ orig_len=len(s)
+ s = JSONComment.remove_comments(s)
+ ret = super().raw_decode(s, idx)
+ return ret[0], orig_len
default_registry = os.path.normpath(os.path.dirname(__file__) + "/../default-registry")
@@ -373,20 +395,20 @@ def obtain_config(settings, args, source_overrides, d):
upstream_config = {'type':'local',
'path':os.path.abspath(config_id),
'name':get_config_name(config_id),
- 'data':json.load(open(config_id))
+ 'data':json.load(open(config_id), cls=JSONComment)
}
elif config_id.startswith("http://") or config_id.startswith("https://"):
print("Reading configuration from network URI\n {}".format(config_id))
import urllib.request
with urllib.request.urlopen(config_id) as f:
- upstream_config = {'type':'network','uri':config_id,'name':get_config_name(config_id),'data':json.load(f)}
+ upstream_config = {'type':'network','uri':config_id,'name':get_config_name(config_id),'data':json.load(f, cls=JSONComment)}
else:
print("Looking up config {} in configuration registry".format(config_id))
registry_path = update_registry(settings["default"]["registry"], cache_dir(args.top_dir), d)
registry_configs = list_registry(registry_path, with_expired=True)
if config_id not in registry_configs:
raise Exception("Config {} not found in configuration registry, re-run 'init' without parameters to choose from available configurations.".format(config_id))
- upstream_config = {'type':'registry','registry':settings["default"]["registry"],'name':config_id,'data':json.load(open(get_registry_config(registry_path,config_id)))}
+ upstream_config = {'type':'registry','registry':settings["default"]["registry"],'name':config_id,'data':json.load(open(get_registry_config(registry_path,config_id)), cls=JSONComment)}
expiry_date = upstream_config['data'].get("expires", None)
if has_expired(expiry_date):
print("This configuration is no longer supported after {}. Please consider changing to a supported configuration.".format(expiry_date))
@@ -395,7 +417,7 @@ def obtain_config(settings, args, source_overrides, d):
registry_configs = list_registry(registry_path, with_expired=True)
config_id = choose_config(registry_configs, args.non_interactive)
config_parameters = []
- upstream_config = {'type':'registry','registry':settings["default"]["registry"],'name':config_id,'data':json.load(open(get_registry_config(registry_path,config_id)))}
+ upstream_config = {'type':'registry','registry':settings["default"]["registry"],'name':config_id,'data':json.load(open(get_registry_config(registry_path,config_id)), cls=JSONComment)}
upstream_config['bitbake-config'] = choose_bitbake_config(upstream_config['data']['bitbake-setup']['configurations'], config_parameters, args.non_interactive)
upstream_config['bitbake-config']['oe-fragment-choices'] = choose_fragments(upstream_config['bitbake-config'].get('oe-fragments-one-of',{}), config_parameters[1:], args.non_interactive, args.skip_selection)
@@ -411,7 +433,7 @@ def init_config(settings, args, d):
progress = event.progress if event.progress > 0 else 0
print("{}% {} ".format(progress, rate), file=stdout, end='\r')
- source_overrides = json.load(open(args.source_overrides)) if args.source_overrides else {'sources':{}}
+ source_overrides = json.load(open(args.source_overrides), cls=JSONComment) if args.source_overrides else {'sources':{}}
upstream_config = obtain_config(settings, args, source_overrides, d)
print("\nRun 'bitbake-setup init --non-interactive {}' to select this configuration non-interactively.\n".format(" ".join(upstream_config['non-interactive-cmdline-options'])))
@@ -492,7 +514,7 @@ def build_status(settings, args, d, update=False):
confdir = os.path.join(builddir, "config")
layerdir = os.path.join(builddir, "layers")
- current_upstream_config = json.load(open(os.path.join(confdir, "config-upstream.json")))
+ current_upstream_config = json.load(open(os.path.join(confdir, "config-upstream.json")), cls=JSONComment)
args.config = current_upstream_config['non-interactive-cmdline-options']
args.non_interactive = True
@@ -560,7 +582,7 @@ def list_registry(registry_path, with_expired):
for f in files:
if f.endswith('.conf.json'):
config_name = get_config_name(f)
- config_data = json.load(open(os.path.join(root, f)))
+ config_data = json.load(open(os.path.join(root, f)), cls=JSONComment)
config_desc = config_data["description"]
expiry_date = config_data.get("expires", None)
if expiry_date:
new file mode 100644
@@ -0,0 +1,82 @@
+{
+ "description": "config to demonstrate inline comments: This is a \"//test", // Inline comment (even "this")
+ "sources": {
+ "bitbake": {
+ "git-remote": {
+ "remotes": {
+ "origin": {
+ "uri": "git://git.openembedded.org/bitbake;protocol=https" // << this is not cut
+ }
+ },
+ "branch": "master",
+ "rev": "master"
+ },
+ "path": "bitbake"
+ },
+ "openembedded-core": {
+ "git-remote": {
+ "remotes": {
+ "origin": {
+ "uri": "git://git.openembedded.org/openembedded-core;protocol=https"
+ }
+ },
+ "branch": "master",
+ "rev": "master"
+ },
+ "path": "openembedded-core"
+ },
+ "meta-yocto": {
+ "git-remote": {
+ "remotes": {
+ "origin": {
+ "uri": "git://git.yoctoproject.org/meta-yocto;protocol=https"
+ }
+ },
+ "branch": "master",
+ "rev": "master"
+ },
+ "path": "meta-yocto"
+ },
+ "yocto-docs": {
+ "git-remote": {
+ "remotes": {
+ "origin": {
+ "uri": "git://git.yoctoproject.org/yocto-docs;protocol=https"
+ }
+ },
+ "branch": "master",
+ "rev": "master"
+ },
+ "path": "yocto-docs"
+ }
+ },
+ "bitbake-setup": {
+ "configurations": [
+ {
+ "bb-layers": ["openembedded-core/meta","meta-yocto/meta-yocto-bsp","meta-yocto/meta-poky"],
+ "oe-fragments-one-of": {
+ "machine": {
+ "description": "Target machines",
+ "options" : ["machine/qemux86-64", "machine/qemuarm64", "machine/qemuriscv64", "machine/genericarm64", "machine/genericx86-64"]
+ },
+ "distro": {
+ "description": "Distribution configuration variants",
+ "options" : ["distro/poky", "distro/poky-altcfg", "distro/poky-tiny"]
+ }
+ },
+ "configurations": [
+ {
+ "name": "poky_jsonc",
+ "description": "Poky - The Yocto Project testing distribution"
+ },
+ {
+ "name": "poky-with-sstate",
+ "description": "Poky - The Yocto Project testing distribution with internet sstate acceleration. Use with caution as it requires a completely robust local network with sufficient bandwidth.",
+ "oe-fragments": ["core/yocto/sstate-mirror-cdn"]
+ }
+ ]
+ }
+ ]
+ },
+ "version": "1.0"
+}