annotations: provide --update command
authorAndrea Righi <andrea.righi@canonical.com>
Fri, 18 Nov 2022 10:22:29 +0000 (11:22 +0100)
committerAndrea Righi <andrea.righi@canonical.com>
Fri, 18 Nov 2022 10:22:29 +0000 (11:22 +0100)
Add a command to import a partial .config (instead of resycning a full
.config as --import does).

Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
annotations
kconfig/annotations.py

index 5673565b81a22a423a1b596a6c3bd68910293bb7..7820fefde4fa447feadffa267f7a238b3a6cdbe7 100755 (executable)
@@ -10,6 +10,13 @@ from kconfig.annotations import Annotation, KConfig
 
 VERSION = '0.1'
 
+SKIP_CONFIGS = (
+    # CONFIG_VERSION_SIGNATURE is dynamically set during the build
+    'CONFIG_VERSION_SIGNATURE',
+    # Allow to use a different version of gcc
+    'CONFIG_CC_VERSION_TEXT',
+)
+
 def make_parser():
     parser = argparse.ArgumentParser(
         description='Manage Ubuntu kernel .config and annotations',
@@ -32,7 +39,10 @@ def make_parser():
                         help='Convert annotations to .config format')
     ga.add_argument('--import', '-i', action='store',
                         metavar="FILE", dest='import_file',
-                        help='Import a .config into annotations')
+                        help='Import a full .config for a specific arch and flavour into annotations')
+    ga.add_argument('--update', '-u', action='store',
+                        metavar="FILE", dest='update_file',
+                        help='Import a partial .config into annotations (only resync configs specified in FILE)')
     ga.add_argument('--check', '-k', action='store',
                         metavar="FILE", dest='check_file',
                         help='Validate kernel .config with annotations')
@@ -59,14 +69,31 @@ def do_export(args):
         print(a.to_config(conf))
 
 def do_import(args):
-    # Determine arch and flavour
     if args.arch is None:
-        arg_fail('error: --arch is required with --import')
+        arg_fail('error: --arch and --flavour are required with --import')
+    if args.flavour is None:
+        arg_fail('error: --arch and --flavour are required with --import')
+    if args.config is not None:
+        arg_fail('error: --config cannot be used with --import (try --update)')
 
     # Merge with the current annotations
+    a = Annotation(args.file)
     c = KConfig(args.import_file)
+    a.update(c, arch=args.arch, flavour=args.flavour)
+
+    # Save back to annotations
+    a.save(args.file)
+
+def do_update(args):
+    if args.arch is None:
+        arg_fail('error: --arch is required with --update')
+
+    # Merge with the current annotations
     a = Annotation(args.file)
-    a.update(c, arch=args.arch, flavour=args.flavour, config=args.config)
+    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)
 
     # Save back to annotations
     a.save(args.file)
@@ -88,12 +115,6 @@ def do_check(args):
     c_configs = c.config.keys()
 
     # Validate .config against annotations
-    SKIP_CONFIGS = (
-        # CONFIG_VERSION_SIGNATURE is dynamically set during the build
-        'CONFIG_VERSION_SIGNATURE',
-        # Allow to use a different version of gcc
-        'CONFIG_CC_VERSION_TEXT',
-    )
     for conf in a_configs | c_configs:
         if conf in SKIP_CONFIGS:
             continue
@@ -133,6 +154,8 @@ def main():
         do_export(args)
     elif args.import_file:
         do_import(args)
+    elif args.update_file:
+        do_update(args)
     elif args.check_file:
         do_check(args)
 
index 92d036f141ba25dee41756143eaf85661fc1fe3e..5d21ef8afa5e919a954b79fe5411380e5c784d15 100644 (file)
@@ -110,22 +110,20 @@ class Annotation(Config):
                 raise Exception(str(e) + f', line = {line}')
         return config
 
-    def update(self, c: KConfig, arch: str, flavour: str = None, config: str = None):
+    def update(self, c: KConfig, arch: str, flavour: str = None, configs: list = []):
         """ Merge configs from a Kconfig object into Annotation object """
 
         # Determine if we need to import all configs or a single config
-        if config is None:
-            a_configs = self.search_config(arch=arch, flavour=flavour).keys()
-            c_configs = c.config.keys()
-        else:
-            a_configs = c_configs = {config}
+        if not configs:
+            configs = c.config.keys()
+            configs |= self.search_config(arch=arch, flavour=flavour).keys()
 
         # Import configs from the Kconfig object into Annotations
         if flavour is not None:
             flavour = arch + f'-{flavour}'
         else:
             flavour = arch
-        for conf in c_configs | a_configs:
+        for conf in configs:
             if conf in c.config:
                 val = c.config[conf]
             else:
@@ -152,7 +150,7 @@ class Annotation(Config):
                     continue
                 arch = m.group(1)
                 if arch not in self.config[conf]['policy']:
-                    self.config[conf]['policy'][arch] = self.config[conf]['policy'][flavour]
+                    continue
                 if self.config[conf]['policy'][flavour] == self.config[conf]['policy'][arch]:
                     del self.config[conf]['policy'][flavour]
 
@@ -178,7 +176,7 @@ class Annotation(Config):
             tmp_a = Annotation(fname)
 
             # Only save local differences (preserve includes)
-            for conf in self.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: