kconfig check: support passing a file directly (!1802)
This allows for example for me to call the kconfig check function on the .config file in my Linux tree: $ pmbootstrap kconfig check --file .config and it reports me which kconfig options I need to enable.
This commit is contained in:
parent
9dc326ecb8
commit
30384b9083
|
@ -247,6 +247,13 @@ def newapkbuild(args):
|
||||||
|
|
||||||
def kconfig(args):
|
def kconfig(args):
|
||||||
if args.action_kconfig == "check":
|
if args.action_kconfig == "check":
|
||||||
|
# Handle passing a file directly
|
||||||
|
if args.file:
|
||||||
|
if pmb.parse.kconfig.check_file(args, args.package, details=True):
|
||||||
|
logging.info("kconfig check succeeded!")
|
||||||
|
return
|
||||||
|
raise RuntimeError("kconfig check failed!")
|
||||||
|
|
||||||
# Default to all kernel packages
|
# Default to all kernel packages
|
||||||
packages = []
|
packages = []
|
||||||
if args.package == "" or args.package is None:
|
if args.package == "" or args.package is None:
|
||||||
|
|
|
@ -227,6 +227,8 @@ def arguments_kconfig(subparser):
|
||||||
" kernels, even the ones that would be ignored by"
|
" kernels, even the ones that would be ignored by"
|
||||||
" default")
|
" default")
|
||||||
check.add_argument("--arch", choices=arch_choices, dest="arch")
|
check.add_argument("--arch", choices=arch_choices, dest="arch")
|
||||||
|
check.add_argument("--file", action="store_true", help="check a file"
|
||||||
|
" directly instead of a config in a package")
|
||||||
check_package = check.add_argument("package", default="", nargs='?')
|
check_package = check.add_argument("package", default="", nargs='?')
|
||||||
if argcomplete:
|
if argcomplete:
|
||||||
check_package.completer = kernel_completer
|
check_package.completer = kernel_completer
|
||||||
|
|
|
@ -35,6 +35,52 @@ def is_set(config, option):
|
||||||
return re.search("^CONFIG_" + option + "=[ym]", config, re.M) is not None
|
return re.search("^CONFIG_" + option + "=[ym]", config, re.M) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def check_config(config_path, config_path_pretty, config_arch, pkgver, details=False):
|
||||||
|
logging.debug("Check kconfig: " + config_path)
|
||||||
|
with open(config_path) as handle:
|
||||||
|
config = handle.read()
|
||||||
|
|
||||||
|
# Loop through necessary config options, and print a warning,
|
||||||
|
# if any is missing
|
||||||
|
ret = True
|
||||||
|
for rule, archs_options in pmb.config.necessary_kconfig_options.items():
|
||||||
|
# Skip options irrelevant for the current kernel's version
|
||||||
|
if not pmb.parse.version.check_string(pkgver, rule):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for archs, options in archs_options.items():
|
||||||
|
if archs != "all":
|
||||||
|
# Split and check if the device's architecture architecture has special config
|
||||||
|
# options. If option does not contain the architecture of the device
|
||||||
|
# kernel, then just skip the option.
|
||||||
|
architectures = archs.split(" ")
|
||||||
|
if config_arch not in architectures:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for option, option_value in options.items():
|
||||||
|
if option_value not in [True, False]:
|
||||||
|
raise RuntimeError("kconfig check code can only handle"
|
||||||
|
" True/False right now, given value '" +
|
||||||
|
str(option_value) + "' is not supported. If you"
|
||||||
|
" need this, please open an issue.")
|
||||||
|
if option_value != is_set(config, option):
|
||||||
|
ret = False
|
||||||
|
if details:
|
||||||
|
should = "should" if option_value else "should *not*"
|
||||||
|
link = ("https://wiki.postmarketos.org/wiki/"
|
||||||
|
"Kernel_configuration#CONFIG_" + option)
|
||||||
|
logging.info("WARNING: " + config_path_pretty + ": CONFIG_" + option + " " +
|
||||||
|
should + " be set. See <" + link +
|
||||||
|
"> for details.")
|
||||||
|
else:
|
||||||
|
logging.warning("WARNING: " + config_path_pretty + " isn't configured"
|
||||||
|
" properly for postmarketOS, run"
|
||||||
|
" 'pmbootstrap kconfig check' for"
|
||||||
|
" details!")
|
||||||
|
break
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def check(args, pkgname, details=False):
|
def check(args, pkgname, details=False):
|
||||||
"""
|
"""
|
||||||
Check for necessary kernel config options.
|
Check for necessary kernel config options.
|
||||||
|
@ -54,50 +100,49 @@ def check(args, pkgname, details=False):
|
||||||
aport = pmb.helpers.pmaports.find(args, "linux-" + flavor)
|
aport = pmb.helpers.pmaports.find(args, "linux-" + flavor)
|
||||||
pkgver = pmb.parse.apkbuild(args, aport + "/APKBUILD")["pkgver"]
|
pkgver = pmb.parse.apkbuild(args, aport + "/APKBUILD")["pkgver"]
|
||||||
for config_path in glob.glob(aport + "/config-*"):
|
for config_path in glob.glob(aport + "/config-*"):
|
||||||
logging.debug("Check kconfig: " + config_path)
|
|
||||||
with open(config_path) as handle:
|
|
||||||
config = handle.read()
|
|
||||||
|
|
||||||
# The architecture of the config is in the name, so it just needs to be
|
# The architecture of the config is in the name, so it just needs to be
|
||||||
# extracted
|
# extracted
|
||||||
config_arch = os.path.basename(config_path).split(".")[1]
|
config_arch = os.path.basename(config_path).split(".")[1]
|
||||||
|
config_path_pretty = "linux-" + flavor + "/" + os.path.basename(config_path)
|
||||||
# Loop trough necessary config options, and print a warning,
|
ret &= check_config(config_path, config_path_pretty, config_arch, pkgver, details)
|
||||||
# if any is missing
|
|
||||||
path = "linux-" + flavor + "/" + os.path.basename(config_path)
|
|
||||||
for rule, archs_options in pmb.config.necessary_kconfig_options.items():
|
|
||||||
# Skip options irrelevant for the current kernel's version
|
|
||||||
if not pmb.parse.version.check_string(pkgver, rule):
|
|
||||||
continue
|
|
||||||
|
|
||||||
for archs, options in archs_options.items():
|
|
||||||
if archs != "all":
|
|
||||||
# Split and check if the device's architecture architecture has special config
|
|
||||||
# options. If option does not contain the architecture of the device
|
|
||||||
# kernel, then just skip the option.
|
|
||||||
architectures = archs.split(" ")
|
|
||||||
if config_arch not in architectures:
|
|
||||||
continue
|
|
||||||
|
|
||||||
for option, option_value in options.items():
|
|
||||||
if option_value not in [True, False]:
|
|
||||||
raise RuntimeError("kconfig check code can only handle"
|
|
||||||
" True/False right now, given value '" +
|
|
||||||
str(option_value) + "' is not supported. If you"
|
|
||||||
" need this, please open an issue.")
|
|
||||||
if option_value != is_set(config, option):
|
|
||||||
ret = False
|
|
||||||
if details:
|
|
||||||
should = "should" if option_value else "should *not*"
|
|
||||||
link = ("https://wiki.postmarketos.org/wiki/"
|
|
||||||
"Kernel_configuration#CONFIG_" + option)
|
|
||||||
logging.info("WARNING: " + path + ": CONFIG_" + option + " " +
|
|
||||||
should + " be set. See <" + link +
|
|
||||||
"> for details.")
|
|
||||||
else:
|
|
||||||
logging.warning("WARNING: " + path + " isn't configured"
|
|
||||||
" properly for postmarketOS, run"
|
|
||||||
" 'pmbootstrap kconfig check' for"
|
|
||||||
" details!")
|
|
||||||
break
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def extract_arch(config_file):
|
||||||
|
# Extract the architecture out of the config
|
||||||
|
with open(config_file) as f:
|
||||||
|
config = f.read()
|
||||||
|
if is_set(config, "ARM"):
|
||||||
|
return "armv7"
|
||||||
|
elif is_set(config, "ARM64"):
|
||||||
|
return "aarch64"
|
||||||
|
elif is_set(config, "X86_32"):
|
||||||
|
return "x86"
|
||||||
|
elif is_set(config, "X86_64"):
|
||||||
|
return "x86_64"
|
||||||
|
|
||||||
|
# No match
|
||||||
|
logging.info("WARNING: failed to extract arch from kernel config")
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
|
||||||
|
def extract_version(config_file):
|
||||||
|
# Try to extract the version string out of the comment header
|
||||||
|
with open(config_file) as f:
|
||||||
|
# Read the first 3 lines of the file and get the third line only
|
||||||
|
text = [next(f) for x in range(3)][2]
|
||||||
|
ver_match = re.match(r"# Linux/\S+ (\S+) Kernel Configuration", text)
|
||||||
|
if ver_match:
|
||||||
|
return ver_match.group(1)
|
||||||
|
|
||||||
|
# No match
|
||||||
|
logging.info("WARNING: failed to extract version from kernel config")
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
|
||||||
|
def check_file(args, config_file, details=False):
|
||||||
|
arch = extract_arch(config_file)
|
||||||
|
version = extract_version(config_file)
|
||||||
|
logging.debug("Check kconfig: parsed arch=" + arch + ", version=" +
|
||||||
|
version + " from file: " + config_file)
|
||||||
|
return check_config(config_file, config_file, arch, version, details)
|
||||||
|
|
Loading…
Reference in New Issue