annotations: include sanitize-annotations into kconfig
authorAndrea Righi <andrea.righi@canonical.com>
Fri, 16 Jun 2023 09:13:51 +0000 (11:13 +0200)
committerAndrea Righi <andrea.righi@canonical.com>
Fri, 16 Jun 2023 10:33:50 +0000 (12:33 +0200)
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
bin/sanitize-annotations [deleted file]
kconfig/run.py
kconfig/sanitize.py [new file with mode: 0755]
kconfig/utils.py [new file with mode: 0644]
setup.cfg
setup.py
snap/snapcraft.yaml

diff --git a/bin/sanitize-annotations b/bin/sanitize-annotations
deleted file mode 100755 (executable)
index 2814f00..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env python3
-#
-# Try to automatically sanitize an old "annotations" file, dropping all the
-# deprecated flags, arbitrary enforcements rules, etc.
-#
-# Usage:
-#  $ ./sanitize-annotations debian.master/config/annotations
-
-import sys
-import re
-
-
-def remove_flags_and_drop_lines(file_path):
-    # Read the contents of the file
-    with open(file_path, "r", encoding="utf-8") as file:
-        content = file.read()
-
-    # Check if the file has the required headers
-    lines = content.splitlines()
-    if (
-        len(lines) < 2
-        or lines[0].strip() != "# Menu: HEADER"
-        or lines[1].strip() != "# FORMAT: 4"
-    ):
-        print(f"ERROR: {file_path} doesn't have a valid header")
-        print("Fix the headers as explained here: " +
-              "https://docs.google.com/document/d/1NnGC2aknyy2TJWMsoYzhrZMr9rYMA09JQBEvC-LW_Lw/")
-        sys.exit(1)
-
-    # Remove unsupported annotations
-    updated_content = re.sub(r"(flag|mark)<.*?>", "", content)
-
-    # Drop lines with a single word and trailing spaces
-    updated_content = re.sub(r"^\w+\s*$", "", updated_content, flags=re.MULTILINE)
-
-    # Add a space after all caps followed by 'policy'
-    updated_content = re.sub(r"([A-Z]+)(policy)", r"\1 \2", updated_content)
-
-    # Add 'note' if missing
-    updated_content = re.sub(r"(\s+)(<.*?>)", r"\1note\2", updated_content)
-
-    # Write the updated contents back to the file
-    with open(file_path, "w", encoding="utf-8") as file:
-        file.write(updated_content)
-
-
-if __name__ == "__main__":
-    file_path = sys.argv[1]
-    remove_flags_and_drop_lines(file_path)
index cfea2e739b598b242f8a2289eb7b66b3bfa4d845..8f24a8dfc54708fed3c2cc6277c724da8f958fde 100644 (file)
@@ -11,8 +11,9 @@ from signal import signal, SIGPIPE, SIG_DFL
 from argcomplete import autocomplete
 
 from kconfig.annotations import Annotation, KConfig
+from kconfig.utils import autodetect_annotations, arg_fail
+from kconfig.version import VERSION
 
-VERSION = "0.1"
 
 SKIP_CONFIGS = (
     # CONFIG_VERSION_SIGNATURE is dynamically set during the build
@@ -117,13 +118,6 @@ def make_parser():
 _ARGPARSER = make_parser()
 
 
-def arg_fail(message, show_usage=True):
-    print(message)
-    if show_usage:
-        _ARGPARSER.print_usage()
-    sys.exit(1)
-
-
 def print_result(config, res):
     if res is not None and config not in res:
         res = {config or "*": res}
@@ -132,7 +126,7 @@ def print_result(config, res):
 
 def do_query(args):
     if args.arch is None and args.flavour is not None:
-        arg_fail("error: --flavour requires --arch")
+        arg_fail(_ARGPARSER, "error: --flavour requires --arch")
     a = Annotation(args.file)
     res = a.search_config(config=args.config, arch=args.arch, flavour=args.flavour)
     print_result(args.config, res)
@@ -147,7 +141,7 @@ def do_autocomplete(args):
 
 def do_source(args):
     if args.config is None:
-        arg_fail("error: --source requires --config")
+        arg_fail(_ARGPARSER, "error: --source requires --config")
     if not os.path.exists("tags"):
         print("tags not found in the current directory, try: `make tags`")
         sys.exit(1)
@@ -156,7 +150,7 @@ def do_source(args):
 
 def do_note(args):
     if args.config is None:
-        arg_fail("error: --note requires --config")
+        arg_fail(_ARGPARSER, "error: --note requires --config")
 
     # Set the note in annotations
     a = Annotation(args.file)
@@ -173,7 +167,7 @@ def do_note(args):
 
 def do_write(args):
     if args.config is None:
-        arg_fail("error: --write requires --config")
+        arg_fail(_ARGPARSER, "error: --write requires --config")
 
     # Set the value in annotations ('null' means remove)
     a = Annotation(args.file)
@@ -199,7 +193,7 @@ def do_write(args):
 
 def do_export(args):
     if args.arch is None:
-        arg_fail("error: --export requires --arch")
+        arg_fail(_ARGPARSER, "error: --export requires --arch")
     a = Annotation(args.file)
     conf = a.search_config(config=args.config, arch=args.arch, flavour=args.flavour)
     if conf:
@@ -208,11 +202,13 @@ def do_export(args):
 
 def do_import(args):
     if args.arch is None:
-        arg_fail("error: --arch is required with --import")
+        arg_fail(_ARGPARSER, "error: --arch is required with --import")
     if args.flavour is None:
-        arg_fail("error: --flavour is required with --import")
+        arg_fail(_ARGPARSER, "error: --flavour is required with --import")
     if args.config is not None:
-        arg_fail("error: --config cannot be used with --import (try --update)")
+        arg_fail(
+            _ARGPARSER, "error: --config cannot be used with --import (try --update)"
+        )
 
     # Merge with the current annotations
     a = Annotation(args.file)
@@ -225,7 +221,7 @@ def do_import(args):
 
 def do_update(args):
     if args.arch is None:
-        arg_fail("error: --arch is required with --update")
+        arg_fail(_ARGPARSER, "error: --arch is required with --update")
 
     # Merge with the current annotations
     a = Annotation(args.file)
@@ -242,7 +238,7 @@ def do_update(args):
 def do_check(args):
     # Determine arch and flavour
     if args.arch is None:
-        arg_fail("error: --arch is required with --check")
+        arg_fail(_ARGPARSER, "error: --arch is required with --check")
 
     print(f"check-config: loading annotations from {args.file}")
     total = good = ret = 0
@@ -276,20 +272,6 @@ def do_check(args):
     sys.exit(ret)
 
 
-def autodetect_annotations(args):
-    if args.file:
-        return
-    # If --file/-f isn't specified try to automatically determine the right
-    # location of the annotations file looking at debian/debian.env.
-    try:
-        with open("debian/debian.env", "rt", encoding="utf-8") as fd:
-            args.file = fd.read().rstrip().split("=")[1] + "/config/annotations"
-    except (FileNotFoundError, IndexError):
-        arg_fail(
-            "error: could not determine DEBDIR, try using: --file/-f", show_usage=False
-        )
-
-
 def main():
     # Prevent broken pipe errors when showing output in pipe to other tools
     # (less for example)
@@ -298,7 +280,15 @@ def main():
     # Main annotations program
     autocomplete(_ARGPARSER)
     args = _ARGPARSER.parse_args()
-    autodetect_annotations(args)
+
+    if args.file is None:
+        args.file = autodetect_annotations()
+        if args.file is None:
+            arg_fail(
+                _ARGPARSER,
+                "error: could not determine DEBDIR, try using: --file/-f",
+                show_usage=False,
+            )
 
     if args.config and not args.config.startswith("CONFIG_"):
         args.config = "CONFIG_" + args.config
diff --git a/kconfig/sanitize.py b/kconfig/sanitize.py
new file mode 100755 (executable)
index 0000000..c393284
--- /dev/null
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+# -*- mode: python -*-
+# Try to automatically sanitize an old annotations file, dropping all the
+# deprecated flags, arbitrary enforcements rules, etc.
+# Copyright © 2023 Canonical Ltd.
+
+import sys
+import re
+import argparse
+from argcomplete import autocomplete
+
+from kconfig.utils import autodetect_annotations, arg_fail
+from kconfig.version import VERSION
+
+
+def make_parser():
+    parser = argparse.ArgumentParser(
+        description="Santizie old Ubuntu kernel annotations file",
+    )
+    parser.add_argument(
+        "--version", "-v", action="version", version=f"%(prog)s {VERSION}"
+    )
+    parser.add_argument(
+        "--file",
+        "-f",
+        action="store",
+        help="Specify annotations file to be sanitized",
+    )
+
+    return parser
+
+
+_ARGPARSER = make_parser()
+
+
+def remove_flags_and_drop_lines(file_path):
+    # Read the contents of the file
+    with open(file_path, "r", encoding="utf-8") as file:
+        content = file.read()
+
+    # Check if the file has the required headers
+    lines = content.splitlines()
+    if (
+        len(lines) < 2
+        or lines[0].strip() != "# Menu: HEADER"
+        or lines[1].strip() != "# FORMAT: 4"
+    ):
+        print(f"ERROR: {file_path} doesn't have a valid header")
+        print(
+            "Fix the headers as explained here: "
+            + "https://discourse.ubuntu.com/t/kernel-configuration-in-ubuntu/35857"
+        )
+        sys.exit(1)
+
+    # Remove unsupported annotations
+    updated_content = re.sub(r"(flag|mark)<.*?>", "", content)
+
+    # Drop lines with a single word and trailing spaces
+    updated_content = re.sub(r"^\w+\s*$", "", updated_content, flags=re.MULTILINE)
+
+    # Add a space after all caps followed by 'policy'
+    updated_content = re.sub(r"([A-Z]+)(policy)", r"\1 \2", updated_content)
+
+    # Add 'note' if missing
+    updated_content = re.sub(r"(\s+)(<.*?>)", r"\1note\2", updated_content)
+
+    # Write the updated contents back to the file
+    with open(file_path, "w", encoding="utf-8") as file:
+        file.write(updated_content)
+
+
+def main():
+    autocomplete(_ARGPARSER)
+    args = _ARGPARSER.parse_args()
+
+    if args.file is None:
+        args.file = autodetect_annotations()
+        if args.file is None:
+            arg_fail(
+                _ARGPARSER,
+                "error: could not determine DEBDIR, try using: --file/-f",
+                show_usage=False,
+            )
+    remove_flags_and_drop_lines(args.file)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/kconfig/utils.py b/kconfig/utils.py
new file mode 100644 (file)
index 0000000..6dd7250
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# -*- mode: python -*-
+# Misc helpers for Kconfig and annotations
+# Copyright © 2023 Canonical Ltd.
+
+import sys
+
+
+def autodetect_annotations():
+    try:
+        with open("debian/debian.env", "rt", encoding="utf-8") as fd:
+            return fd.read().rstrip().split("=")[1] + "/config/annotations"
+    except (FileNotFoundError, IndexError):
+        return None
+
+
+def arg_fail(parser, message, show_usage=True):
+    print(message)
+    if show_usage:
+        parser.print_usage()
+    sys.exit(1)
index 00a726a0c1e3c88482f763732bf17d5107ae6c84..7fc88b31ca0b56653f972fb1d94d7813fe798b8f 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -30,6 +30,7 @@ disable = invalid-name,
           too-many-statements,
           redefined-outer-name,
           # End of default disables
+          similarities,
           too-many-branches,
           too-many-return-statements,
           too-few-public-methods
index cbd0d7103a6918d9e94bcc5fe58f6096ca30cd86..905cf798cd21c9247b53c32d64c047cbf9dd931d 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -20,7 +20,7 @@ class LintCommand(Command):
     def run(self):
         for cmd in ("flake8", "pylint"):
             command = [cmd]
-            for pattern in ("*.py", "kconfig/*.py", "bin/*"):
+            for pattern in ("*.py", "kconfig/*.py"):
                 command += glob(pattern)
             subprocess.call(command)
 
@@ -34,7 +34,7 @@ setup(
     url="https://git.launchpad.net/~arighi/+git/annotations-tools",
     license="GPLv2",
     long_description=open(  # pylint: disable=consider-using-with
-        os.path.join(os.path.dirname(__file__), "README.rst"),
+        os.path.join(os.path.dirname(__file__), "README.md"),
         "r",
         encoding="utf-8",
     ).read(),
@@ -44,14 +44,12 @@ setup(
     entry_points={
         "console_scripts": [
             "annotations = kconfig.run:main",
+            "sanitize-annotations = kconfig.sanitize:main",
         ]
     },
     cmdclass={
         "lint": LintCommand,
     },
-    scripts=[
-        "bin/sanitize-annotations",
-    ],
     include_package_data=True,
     classifiers=[
         "Environment :: Console",
index c7d3a4bac16301ed7a6594e91bd84313dcd17a66..374e58e4c7fca847f4d6b70c047558826041b1e1 100644 (file)
@@ -22,6 +22,13 @@ apps:
     aliases:
       - annotations
 
+  sanitize:
+    command: bin/sanitize-annotations
+    plugs:
+      - home
+    aliases:
+      - sanitize-annotations
+
 parts:
   annotations:
     build-packages: