From: Andrea Righi Date: Mon, 11 Dec 2023 08:49:35 +0000 (+0100) Subject: annotations: introduce --no-include X-Git-Tag: v0.2~10 X-Git-Url: https://jxself.org/git/?a=commitdiff_plain;h=f64bb92e09100c6f7c62bdd818dd093a6e476ff4;p=annotations.git annotations: introduce --no-include Add an option to skip processing included annotations files. This option can be useful to convert files from an old format to a newer one, by dumping the contant of the local leaf-node annotations file, instead of including the content of external files. Signed-off-by: Andrea Righi --- diff --git a/kconfig/annotations.py b/kconfig/annotations.py index e3edfb5..44c6f66 100644 --- a/kconfig/annotations.py +++ b/kconfig/annotations.py @@ -16,12 +16,13 @@ from kconfig.version import ANNOTATIONS_FORMAT_VERSION class Config: - def __init__(self, fname): + def __init__(self, fname, do_include=True): """ Basic configuration file object """ self.fname = fname self.config = {} + self.do_include = do_include raw_data = self._load(fname) self._parse(raw_data) @@ -91,9 +92,10 @@ class Annotation(Config): if m: if parent: self.include.append(m.group(1)) - include_fname = dirname(abspath(self.fname)) + "/" + m.group(1) - include_data = self._load(include_fname) - self._parse_body(include_data, parent=False) + if self.do_include: + include_fname = dirname(abspath(self.fname)) + "/" + m.group(1) + include_data = self._load(include_fname) + self._parse_body(include_data, parent=False) continue # Handle policy and note lines @@ -170,59 +172,60 @@ class Annotation(Config): if not self.flavour: raise SyntaxError(f"FLAVOUR not defined in annotations") - # Parse body (handle includes recursively) + # Parse body self._parse_body(data) # Sanity check: Verify that all FLAVOUR_DEP flavors are valid - for src, tgt in self.flavour_dep.items(): - if src not in self.flavour: - raise SyntaxError(f"Invalid source flavour in FLAVOUR_DEP: {src}") - if tgt not in self.include_flavour: - raise SyntaxError(f"Invalid target flavour in FLAVOUR_DEP: {tgt}") + if self.do_include: + for src, tgt in self.flavour_dep.items(): + if src not in self.flavour: + raise SyntaxError(f"Invalid source flavour in FLAVOUR_DEP: {src}") + 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'] + version = data["attributes"]["_version"] if version > ANNOTATIONS_FORMAT_VERSION: - raise SyntaxError(f"annotations format version {version} not supported") + 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.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'] + 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'])) + 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 = self.flavour_dep | 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) + if self.do_include: + 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: + except SyntaxError as e: self._json_parse(data, is_included=False) def _remove_entry(self, config: str): @@ -295,12 +298,16 @@ class Annotation(Config): if "policy" in self.config[conf]: # Add a TODO if a config with a note is changing and print # a warning - old_val = self.search_config(config=conf, arch=arch, flavour=flavour_arg) + old_val = self.search_config( + config=conf, arch=arch, flavour=flavour_arg + ) if old_val: old_val = old_val[conf] if val != old_val and "note" in self.config[conf]: - self.config[conf]['note'] = "TODO: update note" - print(f"WARNING: {conf} changed from {old_val} to {val}, updating note") + self.config[conf]["note"] = "TODO: update note" + print( + f"WARNING: {conf} changed from {old_val} to {val}, updating note" + ) self.config[conf]["policy"][flavour] = val else: self.config[conf]["policy"] = {flavour: val} diff --git a/kconfig/run.py b/kconfig/run.py index 992dc56..17760c5 100644 --- a/kconfig/run.py +++ b/kconfig/run.py @@ -80,6 +80,11 @@ def make_parser(): action="store_true", help="Jump to a config definition in the kernel source code", ) + parser.add_argument( + "--no-include", + action="store_true", + help="Do not process included annotations (stop at the main file)", + ) ga = parser.add_argument_group(title="Action").add_mutually_exclusive_group( required=False @@ -127,29 +132,34 @@ def make_parser(): _ARGPARSER = make_parser() + def export_result(data): # Dump metadata / attributes first out = '{\n "attributes": {\n' - for key, value in sorted(data['attributes'].items()): + for key, value in sorted(data["attributes"].items()): out += f' "{key}": {json.dumps(value)},\n' - out = out.rstrip(',\n') - out += '\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} + 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'] + 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}' + out = out.rstrip(",\n") + out += "\n }\n}" print(out) @@ -162,7 +172,7 @@ def print_result(config, data): def do_query(args): if args.arch is None and args.flavour is not None: arg_fail(_ARGPARSER, "error: --flavour requires --arch") - a = Annotation(args.file) + a = Annotation(args.file, do_include=(not args.no_include)) res = a.search_config(config=args.config, arch=args.arch, flavour=args.flavour) # 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: