#!/usr/bin/python """Iterate through KConfig options, enabling them one by one.""" import argparse import pathlib import re import subprocess import sys import termcolor import typing parser = argparse.ArgumentParser() parser.add_argument("-q", "--quick", action="store_true", dest="quick", help="Only compile the subdirectory " "containing the Kconfig file") parser.add_argument("kconfig", metavar="Kconfig", nargs=1, help="Path to Kconfig file") parser.add_argument("makeargs", metavar="Make Arguments", nargs="*", help="Options to pass to make") Args = parser.parse_args() Kconfig = pathlib.Path(Args.kconfig[0]) Config = pathlib.Path("scripts/config").absolute() Make = pathlib.Path("~/.local/bin/makelinux.zsh").expanduser() MakeArg = Args.makeargs + ([f"{str(Kconfig)}/"] if Args.quick else []) Options = dict() Colors = {"n": "dark_grey", "y": "green", "m": "cyan"} Attrs = {"y": ["bold"], "m": ["bold"]} NameLen = 0 if Kconfig.is_dir(): Kconfig = Kconfig / "Kconfig" for path in [Kconfig, Make, Config]: if not path.exists(): print(f"Error: {path} does not exist!") sys.exit(1) class Option: """Represents a single CONFIG_* KConfig Option.""" def __init__(self, opt: str): """Initialize our Option class.""" lines = opt.splitlines() self.name = lines[0].strip() self.type = lines[1].strip().split()[0] self.state = "y" self.res = None if search := re.search(r"\sdepends on (.*?)\n", opt): depends = search.group(1).strip() depends = [d.strip() for d in re.split("[&&|=m|=y|=n]", depends)] self.depends = set([d for d in depends if len(d) > 0]) else: self.depends = set() def __repr__(self) -> str: """Return a string representation of this Option.""" return f"{self.name}:{self.type}" def __lt__(self, rhs: typing.Self) -> bool: """Check if this option is less than the `rhs` option.""" if self.name.endswith("DEBUG"): return False if rhs.name.endswith("DEBUG"): return True return self.name in rhs.dependencies() def dependencies(self) -> set[typing.Self]: """Get a set of dependencies for this Option.""" ret = self.depends.copy() for dep in self.depends: if (opt := Options.get(dep)) is not None: ret.update(opt.dependencies()) return ret def disable(self) -> None: """Disable this Option.""" subprocess.run([Config] + ["--disable", self.name]).check_returncode() self.state = "n" def enable(self) -> None: """Enable this Option.""" how = "--module" if self.type == "tristate" else "--enable" subprocess.run([Config] + [how, self.name]).check_returncode() self.state = "m" if self.type == "tristate" else "y" def print(self) -> None: """Print out this option (in color!).""" print(" ", end="") termcolor.cprint(self.name, Colors.get(self.state), attrs=["bold", "dark"], end="") termcolor.cprint("=", "white", attrs=["bold"], end="") termcolor.cprint(self.state, Colors.get(self.state), attrs=["bold", "dark"]) def print_result(self) -> None: """Print out this option and result.""" attrs = [] if self.res is None else ["bold"] match self.res: case True: result = ("Success", "green") case False: result = ("Failed", "red") case _: result = ("Not Run", "yellow") termcolor.cprint(" " + self.name + " ", Colors.get(self.state), attrs=attrs, end="") termcolor.cprint(" " * (NameLen - len(self.name)), "grey", attrs=["underline"], end="") termcolor.cprint(" " + result[0], result[1], attrs=attrs) with open(Kconfig) as f: regex = re.compile("\nconfig") opts = [Option(opt) for opt in regex.split(f.read()) if opt[0] != "#"] Options = {opt.name: opt for opt in opts if opt.type in ["bool", "tristate"]} options = list(sorted(Options.values())) def make_opt(option: Option) -> None: """Enable and build a single option.""" option.enable() print() for o in options: o.print() option.res = False subprocess.run([Make] + ["olddefconfig"]).check_returncode() subprocess.run([Make] + MakeArg).check_returncode() option.res = True try: for opt in options: NameLen = max(NameLen, len(opt.name) + 2) opt.disable() for opt in options: make_opt(opt) except Exception as e: print(str(e)) finally: print() termcolor.cprint("Kconfig Results:", "yellow", attrs=["bold", "underline"]) for opt in options: opt.print_result() if False in [opt.res for opt in options]: sys.exit(1)