pmb.parse.kconfig: implement anbox kconfig check (MR 1916)
fixes https://gitlab.com/postmarketOS/pmbootstrap/-/issues/1891.
This commit is contained in:
parent
e36e160167
commit
28da033267
|
@ -146,4 +146,5 @@ def menuconfig(args, pkgname):
|
||||||
pmb.build.checksum.update(args, pkgname)
|
pmb.build.checksum.update(args, pkgname)
|
||||||
|
|
||||||
# Check config
|
# Check config
|
||||||
pmb.parse.kconfig.check(args, apkbuild["_flavor"], details=True)
|
pmb.parse.kconfig.check(args, apkbuild["_flavor"], force_anbox_check=False,
|
||||||
|
details=True)
|
||||||
|
|
|
@ -208,6 +208,32 @@ necessary_kconfig_options = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Necessary anbox kernel config options
|
||||||
|
necessary_kconfig_options_anbox = {
|
||||||
|
">=0.0.0": { # all versions
|
||||||
|
"all": { # all arches
|
||||||
|
"SQUASHFS": True,
|
||||||
|
"SQUASHFS_XZ": True,
|
||||||
|
"SQUASHFS_XATTR": True,
|
||||||
|
"TMPFS_XATTR": True,
|
||||||
|
"ASHMEM": True,
|
||||||
|
"ANDROID_BINDER_IPC": True,
|
||||||
|
"ANDROID_BINDERFS": False,
|
||||||
|
"ANDROID_BINDER_DEVICES": ["binder", "hwbinder"],
|
||||||
|
"NETFILTER_XTABLES": True,
|
||||||
|
"NETFILTER_XT_MATCH_COMMENT": True,
|
||||||
|
"IP_NF_MANGLE": True,
|
||||||
|
"FUSE_FS": True,
|
||||||
|
"BLK_DEV_LOOP": True,
|
||||||
|
"TUN": True,
|
||||||
|
"VETH": True,
|
||||||
|
"VLAN_8021Q": True, # prerequisite for bridge
|
||||||
|
"BRIDGE": True,
|
||||||
|
"BRIDGE_VLAN_FILTERING": True,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# PARSE
|
# PARSE
|
||||||
#
|
#
|
||||||
|
@ -260,6 +286,7 @@ apkbuild_attributes = {
|
||||||
apkbuild_custom_valid_options = [
|
apkbuild_custom_valid_options = [
|
||||||
"!pmb:crossdirect",
|
"!pmb:crossdirect",
|
||||||
"!pmb:kconfig-check",
|
"!pmb:kconfig-check",
|
||||||
|
"pmb:kconfigcheck-anbox",
|
||||||
"pmb:cross-native",
|
"pmb:cross-native",
|
||||||
"pmb:strict",
|
"pmb:strict",
|
||||||
]
|
]
|
||||||
|
|
|
@ -247,7 +247,9 @@ def kconfig(args):
|
||||||
if args.action_kconfig == "check":
|
if args.action_kconfig == "check":
|
||||||
# Handle passing a file directly
|
# Handle passing a file directly
|
||||||
if args.file:
|
if args.file:
|
||||||
if pmb.parse.kconfig.check_file(args, args.package, details=True):
|
if pmb.parse.kconfig.check_file(args, args.package,
|
||||||
|
force_anbox_check=args.anbox,
|
||||||
|
details=True):
|
||||||
logging.info("kconfig check succeeded!")
|
logging.info("kconfig check succeeded!")
|
||||||
return
|
return
|
||||||
raise RuntimeError("kconfig check failed!")
|
raise RuntimeError("kconfig check failed!")
|
||||||
|
@ -273,7 +275,9 @@ def kconfig(args):
|
||||||
if "!pmb:kconfigcheck" in apkbuild["options"]:
|
if "!pmb:kconfigcheck" in apkbuild["options"]:
|
||||||
skipped += 1
|
skipped += 1
|
||||||
continue
|
continue
|
||||||
if not pmb.parse.kconfig.check(args, package, details=True):
|
if not pmb.parse.kconfig.check(args, package,
|
||||||
|
force_anbox_check=args.anbox,
|
||||||
|
details=True):
|
||||||
error = True
|
error = True
|
||||||
|
|
||||||
# At least one failure
|
# At least one failure
|
||||||
|
|
|
@ -258,6 +258,8 @@ def arguments_kconfig(subparser):
|
||||||
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"
|
check.add_argument("--file", action="store_true", help="check a file"
|
||||||
" directly instead of a config in a package")
|
" directly instead of a config in a package")
|
||||||
|
check.add_argument("--anbox", action="store_true", help="check"
|
||||||
|
" options needed for anbox too")
|
||||||
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
|
||||||
|
|
|
@ -19,15 +19,67 @@ 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):
|
def is_in_array(config, option, string):
|
||||||
|
"""
|
||||||
|
Check, whether a config option contains string as an array element
|
||||||
|
"""
|
||||||
|
match = re.search("^CONFIG_" + option + "=\"(.*)\"$", config, re.M)
|
||||||
|
if match:
|
||||||
|
values = match.group(1).split(",")
|
||||||
|
return string in values
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def check_option(component, details, config, config_path_pretty, option, option_value):
|
||||||
|
link = (f"https://wiki.postmarketos.org/wiki/kconfig#CONFIG_{option}")
|
||||||
|
warning_no_details = (f"WARNING: {config_path_pretty} isn't"
|
||||||
|
f" configured properly for {component}, run"
|
||||||
|
f" 'pmbootstrap kconfig check' for details!")
|
||||||
|
if isinstance(option_value, list):
|
||||||
|
for string in option_value:
|
||||||
|
if not is_in_array(config, option, string):
|
||||||
|
if details:
|
||||||
|
logging.info(f"WARNING: {config_path_pretty}:"
|
||||||
|
f' CONFIG_{option} should contain "{string}".'
|
||||||
|
f" See <{link}> for details.")
|
||||||
|
else:
|
||||||
|
logging.warning(warning_no_details)
|
||||||
|
return False
|
||||||
|
elif option_value in [True, False]:
|
||||||
|
if option_value != is_set(config, option):
|
||||||
|
if details:
|
||||||
|
should = "should" if option_value else "should *not*"
|
||||||
|
logging.info(f"WARNING: {config_path_pretty}: CONFIG_{option}"
|
||||||
|
f" {should} be set. See <{link}> for details.")
|
||||||
|
else:
|
||||||
|
logging.warning(warning_no_details)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
raise RuntimeError("kconfig check code can only handle True/False and"
|
||||||
|
" arrays now, given value '" + str(option_value) +
|
||||||
|
"' is not supported. If you need this, please open"
|
||||||
|
" an issue.")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def check_config(config_path, config_path_pretty, config_arch, pkgver,
|
||||||
|
anbox=False, details=False):
|
||||||
logging.debug("Check kconfig: " + config_path)
|
logging.debug("Check kconfig: " + config_path)
|
||||||
with open(config_path) as handle:
|
with open(config_path) as handle:
|
||||||
config = handle.read()
|
config = handle.read()
|
||||||
|
|
||||||
|
if anbox:
|
||||||
|
options = pmb.config.necessary_kconfig_options_anbox
|
||||||
|
component = "anbox"
|
||||||
|
else:
|
||||||
|
options = pmb.config.necessary_kconfig_options
|
||||||
|
component = "postmarketOS"
|
||||||
|
|
||||||
# Loop through necessary config options, and print a warning,
|
# Loop through necessary config options, and print a warning,
|
||||||
# if any is missing
|
# if any is missing
|
||||||
ret = True
|
ret = True
|
||||||
for rule, archs_options in pmb.config.necessary_kconfig_options.items():
|
for rule, archs_options in options.items():
|
||||||
# Skip options irrelevant for the current kernel's version
|
# Skip options irrelevant for the current kernel's version
|
||||||
if not pmb.parse.version.check_string(pkgver, rule):
|
if not pmb.parse.version.check_string(pkgver, rule):
|
||||||
continue
|
continue
|
||||||
|
@ -42,32 +94,16 @@ def check_config(config_path, config_path_pretty, config_arch, pkgver, details=F
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for option, option_value in options.items():
|
for option, option_value in options.items():
|
||||||
if option_value not in [True, False]:
|
if not check_option(component, details, config, config_path_pretty, option, option_value):
|
||||||
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
|
ret = False
|
||||||
if details:
|
if not details:
|
||||||
should = "should" if option_value else "should *not*"
|
break # do not give too much error messages
|
||||||
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
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def check(args, pkgname, details=False):
|
def check(args, pkgname, force_anbox_check=False, details=False):
|
||||||
"""
|
"""
|
||||||
Check for necessary kernel config options.
|
Check for necessary kernel config options in a package.
|
||||||
|
|
||||||
:returns: True when the check was successful, False otherwise
|
:returns: True when the check was successful, False otherwise
|
||||||
"""
|
"""
|
||||||
|
@ -82,13 +118,19 @@ def check(args, pkgname, details=False):
|
||||||
# Read all kernel configs in the aport
|
# Read all kernel configs in the aport
|
||||||
ret = True
|
ret = True
|
||||||
aport = pmb.helpers.pmaports.find(args, "linux-" + flavor)
|
aport = pmb.helpers.pmaports.find(args, "linux-" + flavor)
|
||||||
pkgver = pmb.parse.apkbuild(args, aport + "/APKBUILD")["pkgver"]
|
apkbuild = pmb.parse.apkbuild(args, aport + "/APKBUILD")
|
||||||
|
pkgver = apkbuild["pkgver"]
|
||||||
|
check_anbox = force_anbox_check or ("pmb:kconfigcheck-anbox" in apkbuild["options"])
|
||||||
for config_path in glob.glob(aport + "/config-*"):
|
for config_path in glob.glob(aport + "/config-*"):
|
||||||
# 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)
|
config_path_pretty = "linux-" + flavor + "/" + os.path.basename(config_path)
|
||||||
ret &= check_config(config_path, config_path_pretty, config_arch, pkgver, details)
|
ret &= check_config(config_path, config_path_pretty, config_arch,
|
||||||
|
pkgver, details=details)
|
||||||
|
if check_anbox:
|
||||||
|
ret &= check_config(config_path, config_path_pretty, config_arch,
|
||||||
|
pkgver, anbox=True, details=details)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,9 +166,19 @@ def extract_version(config_file):
|
||||||
return "unknown"
|
return "unknown"
|
||||||
|
|
||||||
|
|
||||||
def check_file(args, config_file, details=False):
|
def check_file(args, config_file, anbox=False, details=False):
|
||||||
|
"""
|
||||||
|
Check for necessary kernel config options in a kconfig file.
|
||||||
|
|
||||||
|
:returns: True when the check was successful, False otherwise
|
||||||
|
"""
|
||||||
arch = extract_arch(config_file)
|
arch = extract_arch(config_file)
|
||||||
version = extract_version(config_file)
|
version = extract_version(config_file)
|
||||||
logging.debug("Check kconfig: parsed arch=" + arch + ", version=" +
|
logging.debug("Check kconfig: parsed arch=" + arch + ", version=" +
|
||||||
version + " from file: " + config_file)
|
version + " from file: " + config_file)
|
||||||
return check_config(config_file, config_file, arch, version, details)
|
ret = check_config(config_file, config_file, arch, version, anbox=False,
|
||||||
|
details=details)
|
||||||
|
if anbox:
|
||||||
|
ret &= check_config(config_file, config_file, arch, version, anbox=True,
|
||||||
|
details=details)
|
||||||
|
return ret
|
||||||
|
|
Loading…
Reference in New Issue