sanitycheck: Add functions to query device tree for filters
Add the following functions to allow filtering based on device tree dt_compat_enabled(compat) - Returns true if a device tree node compatible matches 'compat' and the node is enabled. dt_alias_exists(alias) - Returns true if a device tree node exists with 'alias' and the node is enabled. dt_compat_enabled_with_alias - Returns true if a device tree node compatible matches 'compat' and the node has 'alias' and the node is enabled. Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
This commit is contained in:
parent
1acea13767
commit
7733b94224
2 changed files with 51 additions and 13 deletions
|
@ -134,6 +134,20 @@ def p_expr_single(p):
|
||||||
"""expr : SYMBOL"""
|
"""expr : SYMBOL"""
|
||||||
p[0] = ("exists", p[1])
|
p[0] = ("exists", p[1])
|
||||||
|
|
||||||
|
def p_func(p):
|
||||||
|
"""expr : SYMBOL OPAREN arg_intr CPAREN"""
|
||||||
|
p[0] = [p[1]]
|
||||||
|
p[0].append(p[3])
|
||||||
|
|
||||||
|
def p_arg_intr_single(p):
|
||||||
|
"""arg_intr : const"""
|
||||||
|
p[0] = [p[1]]
|
||||||
|
|
||||||
|
def p_arg_intr_mult(p):
|
||||||
|
"""arg_intr : arg_intr COMMA const"""
|
||||||
|
p[0] = copy.copy(p[1])
|
||||||
|
p[0].append(p[3])
|
||||||
|
|
||||||
def p_list(p):
|
def p_list(p):
|
||||||
"""list : OBRACKET list_intr CBRACKET"""
|
"""list : OBRACKET list_intr CBRACKET"""
|
||||||
p[0] = p[2]
|
p[0] = p[2]
|
||||||
|
@ -182,13 +196,13 @@ def ast_sym_int(ast, env):
|
||||||
return int(v, 10)
|
return int(v, 10)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def ast_expr(ast, env):
|
def ast_expr(ast, env, edt):
|
||||||
if ast[0] == "not":
|
if ast[0] == "not":
|
||||||
return not ast_expr(ast[1], env)
|
return not ast_expr(ast[1], env, edt)
|
||||||
elif ast[0] == "or":
|
elif ast[0] == "or":
|
||||||
return ast_expr(ast[1], env) or ast_expr(ast[2], env)
|
return ast_expr(ast[1], env, edt) or ast_expr(ast[2], env, edt)
|
||||||
elif ast[0] == "and":
|
elif ast[0] == "and":
|
||||||
return ast_expr(ast[1], env) and ast_expr(ast[2], env)
|
return ast_expr(ast[1], env, edt) and ast_expr(ast[2], env, edt)
|
||||||
elif ast[0] == "==":
|
elif ast[0] == "==":
|
||||||
return ast_sym(ast[1], env) == ast[2]
|
return ast_sym(ast[1], env) == ast[2]
|
||||||
elif ast[0] == "!=":
|
elif ast[0] == "!=":
|
||||||
|
@ -207,10 +221,29 @@ def ast_expr(ast, env):
|
||||||
return bool(ast_sym(ast[1], env))
|
return bool(ast_sym(ast[1], env))
|
||||||
elif ast[0] == ":":
|
elif ast[0] == ":":
|
||||||
return bool(re.match(ast[2], ast_sym(ast[1], env)))
|
return bool(re.match(ast[2], ast_sym(ast[1], env)))
|
||||||
|
elif ast[0] == "dt_compat_enabled":
|
||||||
|
compat = ast[1][0]
|
||||||
|
for node in edt.nodes:
|
||||||
|
if compat in node.compats and node.enabled:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
elif ast[0] == "dt_alias_exists":
|
||||||
|
alias = ast[1][0]
|
||||||
|
for node in edt.nodes:
|
||||||
|
if alias in node.aliases and node.enabled:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
elif ast[0] == "dt_compat_enabled_with_alias":
|
||||||
|
compat = ast[1][0]
|
||||||
|
alias = ast[1][1]
|
||||||
|
for node in edt.nodes:
|
||||||
|
if node.enabled and alias in node.aliases and node.matching_compat == compat:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
mutex = threading.Lock()
|
mutex = threading.Lock()
|
||||||
|
|
||||||
def parse(expr_text, env):
|
def parse(expr_text, env, edt):
|
||||||
"""Given a text representation of an expression in our language,
|
"""Given a text representation of an expression in our language,
|
||||||
use the provided environment to determine whether the expression
|
use the provided environment to determine whether the expression
|
||||||
is true or false"""
|
is true or false"""
|
||||||
|
@ -222,7 +255,7 @@ def parse(expr_text, env):
|
||||||
finally:
|
finally:
|
||||||
mutex.release()
|
mutex.release()
|
||||||
|
|
||||||
return ast_expr(ast, env)
|
return ast_expr(ast, env, edt)
|
||||||
|
|
||||||
# Just some test code
|
# Just some test code
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -244,4 +277,4 @@ if __name__ == "__main__":
|
||||||
parser = yacc.yacc()
|
parser = yacc.yacc()
|
||||||
print(parser.parse(line))
|
print(parser.parse(line))
|
||||||
|
|
||||||
print(parse(line, local_env))
|
print(parse(line, local_env, None))
|
||||||
|
|
|
@ -199,6 +199,13 @@ from itertools import islice
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from distutils.spawn import find_executable
|
from distutils.spawn import find_executable
|
||||||
|
|
||||||
|
ZEPHYR_BASE = os.getenv("ZEPHYR_BASE")
|
||||||
|
if not ZEPHYR_BASE:
|
||||||
|
sys.exit("$ZEPHYR_BASE environment variable undefined")
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts", "dts"))
|
||||||
|
import edtlib
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
@ -209,11 +216,6 @@ report_lock = threading.Lock()
|
||||||
log_format = "%(levelname)s %(name)s::%(module)s.%(funcName)s():%(lineno)d: %(message)s"
|
log_format = "%(levelname)s %(name)s::%(module)s.%(funcName)s():%(lineno)d: %(message)s"
|
||||||
logging.basicConfig(format=log_format, level=30)
|
logging.basicConfig(format=log_format, level=30)
|
||||||
|
|
||||||
ZEPHYR_BASE = os.environ.get("ZEPHYR_BASE")
|
|
||||||
if not ZEPHYR_BASE:
|
|
||||||
sys.stderr.write("$ZEPHYR_BASE environment variable undefined.\n")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# Use this for internal comparisons; that's what canonicalization is
|
# Use this for internal comparisons; that's what canonicalization is
|
||||||
# for. Don't use it when invoking other components of the build system
|
# for. Don't use it when invoking other components of the build system
|
||||||
# to avoid confusing and hard to trace inconsistencies in error messages
|
# to avoid confusing and hard to trace inconsistencies in error messages
|
||||||
|
@ -1902,7 +1904,10 @@ class FilterBuilder(CMake):
|
||||||
|
|
||||||
if self.testcase and self.testcase.tc_filter:
|
if self.testcase and self.testcase.tc_filter:
|
||||||
try:
|
try:
|
||||||
res = expr_parser.parse(self.testcase.tc_filter, filter_data)
|
dts_path = os.path.join(self.build_dir, "zephyr", self.platform.name + ".dts.pre.tmp")
|
||||||
|
edt = edtlib.EDT(dts_path, [os.path.join(ZEPHYR_BASE, "dts", "bindings")])
|
||||||
|
res = expr_parser.parse(self.testcase.tc_filter, filter_data, edt)
|
||||||
|
|
||||||
except (ValueError, SyntaxError) as se:
|
except (ValueError, SyntaxError) as se:
|
||||||
sys.stderr.write(
|
sys.stderr.write(
|
||||||
"Failed processing %s\n" % self.testcase.yamlfile)
|
"Failed processing %s\n" % self.testcase.yamlfile)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue