From e11d2512e79068c29001eaea7d1217dc845f2b80 Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Fri, 16 Jun 2023 11:13:51 +0200 Subject: [PATCH] annotations: include sanitize-annotations into kconfig Signed-off-by: Andrea Righi --- bin/sanitize-annotations | 49 ---------------------- kconfig/run.py | 56 +++++++++++-------------- kconfig/sanitize.py | 88 ++++++++++++++++++++++++++++++++++++++++ kconfig/utils.py | 21 ++++++++++ setup.cfg | 1 + setup.py | 8 ++-- snap/snapcraft.yaml | 7 ++++ 7 files changed, 143 insertions(+), 87 deletions(-) delete mode 100755 bin/sanitize-annotations create mode 100755 kconfig/sanitize.py create mode 100644 kconfig/utils.py diff --git a/bin/sanitize-annotations b/bin/sanitize-annotations deleted file mode 100755 index 2814f00..0000000 --- a/bin/sanitize-annotations +++ /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) diff --git a/kconfig/run.py b/kconfig/run.py index cfea2e7..8f24a8d 100644 --- a/kconfig/run.py +++ b/kconfig/run.py @@ -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 index 0000000..c393284 --- /dev/null +++ b/kconfig/sanitize.py @@ -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 index 0000000..6dd7250 --- /dev/null +++ b/kconfig/utils.py @@ -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) diff --git a/setup.cfg b/setup.cfg index 00a726a..7fc88b3 100644 --- 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 diff --git a/setup.py b/setup.py index cbd0d71..905cf79 100755 --- 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", diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index c7d3a4b..374e58e 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -22,6 +22,13 @@ apps: aliases: - annotations + sanitize: + command: bin/sanitize-annotations + plugs: + - home + aliases: + - sanitize-annotations + parts: annotations: build-packages: -- 2.31.1