From a4580dbdb5d27fba1c3bd9747aab554c10ef22c6 Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Sat, 3 Dec 2022 13:06:03 +0100 Subject: [PATCH] annotations: support flavour dependencies (flavour inheritance) Allow to define flavour inheritance relationship in the annotations file, such as: # FLAVOUR_DEP: {'amd64-lowlatency': 'amd64-generic', 'arm64-lowlatency': 'arm64-generic', 'arm64-lowlatency-64k': 'arm64-lowlatency-64k'} In this case, for example, -lowlatency flavours inherits the config values from -generic (both for amd64 and arm64) and -lowlatency-64 inherits the value from -generic-64k (only on arm64). This allows to strongly reduce the size of annotations and helps to read and review changes in annotations. Signed-off-by: Andrea Righi --- annotations | 18 +++++++++++---- kconfig/annotations.py | 51 +++++++++++++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/annotations b/annotations index c437787..37f7987 100755 --- a/annotations +++ b/annotations @@ -60,13 +60,20 @@ def arg_fail(message): _ARGPARSER.print_usage() exit(1) +def print_result(config, res): + if res is not None and config not in res: + res = {config or '*': res} + print(json.dumps(res, indent=4)) + def do_query(args): + if args.arch is None and args.flavour is not None: + arg_fail('error: --flavour requires --arch') a = Annotation(args.file) for config in (args.config, 'CONFIG_' + args.config if args.config else None): res = a.search_config(config=config, arch=args.arch, flavour=args.flavour) if res: break - print(json.dumps({config or '*': res}, indent=4)) + print_result(config, res) def do_note(args): if args.config is None: @@ -80,8 +87,9 @@ def do_note(args): a.save(args.file) # Query and print back the value + a = Annotation(args.file) res = a.search_config(config=args.config) - print(json.dumps(res, indent=4)) + print_result(args.config, res) def do_write(args): if args.config is None: @@ -98,8 +106,9 @@ def do_write(args): a.save(args.file) # Query and print back the value + a = Annotation(args.file) res = a.search_config(config=args.config) - print(json.dumps(res, indent=4)) + print_result(args.config, res) def do_export(args): if args.arch is None: @@ -134,7 +143,8 @@ def do_update(args): c = KConfig(args.update_file) if args.config is None: configs = list(set(c.config.keys()) - set(SKIP_CONFIGS)) - a.update(c, arch=args.arch, flavour=args.flavour, configs=configs) + if configs: + a.update(c, arch=args.arch, flavour=args.flavour, configs=configs) # Save back to annotations a.save(args.file) diff --git a/kconfig/annotations.py b/kconfig/annotations.py index fd43a90..7645fd1 100644 --- a/kconfig/annotations.py +++ b/kconfig/annotations.py @@ -52,8 +52,11 @@ class Annotation(Config): .config[] """ def _parse(self, data: str) -> dict: - # Parse header + self.arch = [] + self.flavour = [] + self.flavour_dep = {} self.header = '' + # Parse header for line in data.splitlines(): if re.match(r'^#.*', line): m = re.match(r'^# ARCH: (.*)', line) @@ -62,6 +65,9 @@ class Annotation(Config): m = re.match(r'^# FLAVOUR: (.*)', line) if m: self.flavour = list(m.group(1).split(' ')) + m = re.match(r'^# FLAVOUR_DEP: (.*)', line) + if m: + self.flavour_dep = eval(m.group(1)) self.header += line + "\n" else: break @@ -178,7 +184,7 @@ class Annotation(Config): def _compact(self): # Try to remove redundant settings: if the config value of a flavour is # the same as the one of the main arch simply drop it. - for conf in self.config: + for conf in self.config.copy(): if 'policy' not in self.config[conf]: continue for flavour in self.flavour: @@ -188,10 +194,22 @@ class Annotation(Config): if not m: continue arch = m.group(1) - if arch not in self.config[conf]['policy']: + if arch in self.config[conf]['policy']: + if self.config[conf]['policy'][flavour] == self.config[conf]['policy'][arch]: + del self.config[conf]['policy'][flavour] + continue + if flavour not in self.flavour_dep: continue - if self.config[conf]['policy'][flavour] == self.config[conf]['policy'][arch]: + generic = self.flavour_dep[flavour] + if generic in self.config[conf]['policy']: + if self.config[conf]['policy'][flavour] == self.config[conf]['policy'][generic]: + del self.config[conf]['policy'][flavour] + continue + for flavour in self.config[conf]['policy'].copy(): + if flavour not in list(set(self.arch + self.flavour)): del self.config[conf]['policy'][flavour] + if not self.config[conf]['policy']: + del self.config[conf] def save(self, fname: str): """ Save annotations data to the annotation file """ @@ -218,13 +236,16 @@ class Annotation(Config): for conf in sorted(self.config): old_val = tmp_a.config[conf] if conf in tmp_a.config else None new_val = self.config[conf] - if old_val != new_val: - if 'policy' in self.config[conf]: - val = dict(sorted(self.config[conf]['policy'].items())) - line = f"{conf : <47} policy<{val}>" - tmp.write(line + "\n") - if 'note' in self.config[conf]: - val = self.config[conf]['note'] + # If new_val is a subset of old_val, skip it + if old_val and 'policy' in old_val and 'policy' in new_val: + if old_val['policy'] == old_val['policy'] | new_val['policy']: + continue + if 'policy' in new_val: + val = dict(sorted(new_val['policy'].items())) + line = f"{conf : <47} policy<{val}>" + tmp.write(line + "\n") + if 'note' in new_val: + val = new_val['note'] line = f"{conf : <47} note<{val}>" tmp.write(line + "\n\n") @@ -237,6 +258,10 @@ class Annotation(Config): if flavour is None: flavour = 'generic' flavour = f'{arch}-{flavour}' + if flavour in self.flavour_dep: + generic = self.flavour_dep[flavour] + else: + generic = flavour if config is None and arch is None: # Get all config options for all architectures return self.config @@ -248,6 +273,8 @@ class Annotation(Config): continue if flavour in self.config[c]['policy']: ret[c] = self.config[c]['policy'][flavour] + elif generic != flavour and generic in self.config[c]['policy']: + ret[c] = self.config[c]['policy'][generic] elif arch in self.config[c]['policy']: ret[c] = self.config[c]['policy'][arch] return ret @@ -260,6 +287,8 @@ class Annotation(Config): if 'policy' in self.config[config]: if flavour in self.config[config]['policy']: return {config: self.config[config]['policy'][flavour]} + elif generic != flavour and generic in self.config[config]['policy']: + return {config: self.config[config]['policy'][generic]} elif arch in self.config[config]['policy']: return {config: self.config[config]['policy'][arch]} return None -- 2.31.1