from ast import literal_eval
from os.path import dirname, abspath
+from kconfig.version import ANNOTATIONS_FORMAT_VERSION
+
class Config:
def __init__(self, fname):
# Invalid line
raise SyntaxError(f"invalid line: {line}")
- def _parse(self, data: str):
+ def _legacy_parse(self, data: str):
"""
Parse main annotations file, individual config options can be accessed
via self.config[<CONFIG_OPTION>]
else:
break
+ # Return an error if architectures are not defined
+ if not self.arch:
+ raise SyntaxError(f"ARCH not defined in annotations")
+ # Return an error if flavours are not defined
+ if not self.flavour:
+ raise SyntaxError(f"FLAVOUR not defined in annotations")
+
# Parse body (handle includes recursively)
self._parse_body(data)
if tgt not in self.include_flavour:
raise SyntaxError(f"Invalid target flavour in FLAVOUR_DEP: {tgt}")
+ def _json_parse(self, data, is_included=False):
+ data = json.loads(data)
+
+ # Check if version is supported
+ version = data['attributes']['_version']
+ if version > ANNOTATIONS_FORMAT_VERSION:
+ raise SyntaxError(f"annotations format version {version} not supported")
+
+ # Check for top-level annotations vs imported annotations
+ if not is_included:
+ self.config = data['config']
+ self.arch = data['attributes']['arch']
+ self.flavour = data['attributes']['flavour']
+ self.flavour_dep = data['attributes']['flavour_dep']
+ self.include = data['attributes']['include']
+ self.include_flavour = []
+ else:
+ # We are procesing an imported annotations, so merge all the
+ # configs and attributes.
+ try:
+ self.config |= data['config']
+ except TypeError:
+ self.config = {
+ **self.config,
+ **data['config']
+ }
+ self.arch = list(set(self.arch) | set(data['attributes']['arch']))
+ self.flavour = list(set(self.flavour) | set(data['attributes']['flavour']))
+ self.include_flavour = list(set(self.include_flavour) | set(data['attributes']['flavour']))
+ self.flavour_dep = list(set(self.flavour_dep) | set(data['attributes']['flavour_dep']))
+
+ # Handle recursive inclusions
+ for f in data['attributes']['include']:
+ include_fname = dirname(abspath(self.fname)) + "/" + f
+ data = self._load(include_fname)
+ self._json_parse(data, is_included=True)
+
+ def _parse(self, data: str):
+ # Try to parse the legacy format first, otherwise use the new JSON
+ # format.
+ try:
+ self._legacy_parse(data)
+ except SyntaxError:
+ self._json_parse(data, is_included=False)
+
def _remove_entry(self, config: str):
if self.config[config]:
del self.config[config]
from kconfig.annotations import Annotation, KConfig
from kconfig.utils import autodetect_annotations, arg_fail
-from kconfig.version import VERSION
+from kconfig.version import VERSION, ANNOTATIONS_FORMAT_VERSION
SKIP_CONFIGS = (
_ARGPARSER = make_parser()
+def export_result(data):
+ # Dump metadata / attributes first
+ out = '{\n "attributes": {\n'
+ for key, value in sorted(data['attributes'].items()):
+ out += f' "{key}": {json.dumps(value)},\n'
+ out = out.rstrip(',\n')
+ out += '\n },'
+ print(out)
+
+ configs_with_note = {key: value for key, value in data['config'].items() if 'note' in value}
+ configs_without_note = {key: value for key, value in data['config'].items() if 'note' not in value}
+
+ # Dump configs, sorted alphabetically, showing items with a note first
+ out = ' "config": {\n'
+ for key in sorted(configs_with_note) + sorted(configs_without_note):
+ policy = data['config'][key]['policy']
+ if 'note' in data['config'][key]:
+ note = data['config'][key]['note']
+ out += f' "{key}": {{"policy": {json.dumps(policy)}, "note": {json.dumps(note)}}},\n'
+ else:
+ out += f' "{key}": {{"policy": {json.dumps(policy)}}},\n'
+ out = out.rstrip(',\n')
+ out += '\n }\n}'
+ print(out)
+
-def print_result(config, res):
- if res is not None and config is not None and config not in res:
- res = {config: res}
- print(json.dumps(res, indent=4))
+def print_result(config, data):
+ if data is not None and config is not None and config not in data:
+ data = {config: data}
+ print(json.dumps(data, sort_keys=True, indent=2))
def do_query(args):
# If no arguments are specified dump the whole annotations structure
if args.config is None and args.arch is None and args.flavour is None:
res = {
- "arch": a.arch,
- "flavour": a.flavour,
- "flavour_dep": a.flavour_dep,
+ "attributes": {
+ "arch": a.arch,
+ "flavour": a.flavour,
+ "flavour_dep": a.flavour_dep,
+ "include": a.include,
+ "_version": ANNOTATIONS_FORMAT_VERSION,
+ },
"config": res,
}
- print_result(args.config, res)
+ export_result(res)
+ else:
+ print_result(args.config, res)
def do_autocomplete(args):