UBUNTU: [Packaging] annotations: support 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 <andrea.righi@canonical.com>
This commit is contained in:
Andrea Righi
2022-12-04 14:13:10 +01:00
committed by Paolo Pisati
parent 0150aad67d
commit 0ab043100c
2 changed files with 54 additions and 15 deletions
+14 -4
View File
@@ -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)
+40 -11
View File
@@ -52,8 +52,11 @@ class Annotation(Config):
.config[<CONFIG_OPTION>]
"""
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