diff --git a/makekconfig.py b/makekconfig.py index 051cbb9..09dd2aa 100755 --- a/makekconfig.py +++ b/makekconfig.py @@ -1,117 +1,151 @@ #!/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") + 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() +Args = parser.parse_args() Kconfig = pathlib.Path(Args.kconfig[0]) -Config = pathlib.Path("scripts/config").absolute() -Make = pathlib.Path("~/bin/makelinux.zsh").expanduser() -MakeArg = Args.makeargs + ([ f"{str(Kconfig)}/" ] if Args.quick else [ ]) +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" : "grey", "y" : "green", "m" : "cyan" } -Attrs = { "y" : [ "bold" ], "m" : [ "bold" ] } +Colors = {"n": "dark_grey", "y": "green", "m": "cyan"} +Attrs = {"y": ["bold"], "m": ["bold"]} NameLen = 0 if Kconfig.is_dir(): Kconfig = Kconfig / "Kconfig" -def assert_exists(path): + +for path in [Kconfig, Make, Config]: if not path.exists(): print(f"Error: {path} does not exist!") sys.exit(1) -assert_exists(Kconfig) -assert_exists(Make) -assert_exists(Config) class Option: - def __init__(self, opt): + """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("\sdepends on (.*?)\n", opt): + 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 ]) + 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): + def __repr__(self) -> str: + """Return a string representation of this Option.""" return f"{self.name}:{self.type}" - def __lt__(self, rhs): - if self.name.endswith("DEBUG"): return False - if rhs.name.endswith("DEBUG"): return True + 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): + 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): - subprocess.run([ Config ] + [ "--disable", self.name ]).check_returncode() + def disable(self) -> None: + """Disable this Option.""" + subprocess.run([Config] + ["--disable", self.name]).check_returncode() self.state = "n" - def enable(self): + def enable(self) -> None: + """Enable this Option.""" how = "--module" if self.type == "tristate" else "--enable" - subprocess.run([ Config ] + [ how, self.name ]).check_returncode() + subprocess.run([Config] + [how, self.name]).check_returncode() self.state = "m" if self.type == "tristate" else "y" - def print(self): + 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(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"]) + 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"] - def print_result(self): 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=["bold", "dark"], end="") - termcolor.cprint(" " * (NameLen - len(self.name)), "grey", attrs=["underline"], end="") - termcolor.cprint(" " + result[0], result[1], attrs=["bold", "dark"]) + + 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" ]} + 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(Options.values()) -options.sort() +options = list(sorted(Options.values())) -def make_opt(option): + +def make_opt(option: Option) -> None: + """Enable and build a single option.""" option.enable() + print() - for o in options: o.print() + for o in options: + o.print() + option.res = False - subprocess.run([ Make ] + [ "olddefconfig" ]).check_returncode() - subprocess.run([ Make ] + MakeArg).check_returncode() + 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) - for opt in options: opt.disable() - for opt in options: make_opt(opt) + 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: - termcolor.cprint(f"\nKconfig Results:", "yellow", attrs=["bold", "underline"]) - for opt in options: opt.print_result() - if False in [ opt.res for opt in options ]: sys.exit(1) + 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)