scripts/makekconfig.py

152 lines
4.9 KiB
Python
Raw Permalink Normal View History

#!/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)