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:
Kumar Gala 2019-09-12 17:08:43 -05:00 committed by Anas Nashif
commit 7733b94224
2 changed files with 51 additions and 13 deletions

View file

@ -134,6 +134,20 @@ def p_expr_single(p):
"""expr : SYMBOL"""
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):
"""list : OBRACKET list_intr CBRACKET"""
p[0] = p[2]
@ -182,13 +196,13 @@ def ast_sym_int(ast, env):
return int(v, 10)
return 0
def ast_expr(ast, env):
def ast_expr(ast, env, edt):
if ast[0] == "not":
return not ast_expr(ast[1], env)
return not ast_expr(ast[1], env, edt)
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":
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] == "==":
return ast_sym(ast[1], env) == ast[2]
elif ast[0] == "!=":
@ -207,10 +221,29 @@ def ast_expr(ast, env):
return bool(ast_sym(ast[1], env))
elif ast[0] == ":":
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()
def parse(expr_text, env):
def parse(expr_text, env, edt):
"""Given a text representation of an expression in our language,
use the provided environment to determine whether the expression
is true or false"""
@ -222,7 +255,7 @@ def parse(expr_text, env):
finally:
mutex.release()
return ast_expr(ast, env)
return ast_expr(ast, env, edt)
# Just some test code
if __name__ == "__main__":
@ -244,4 +277,4 @@ if __name__ == "__main__":
parser = yacc.yacc()
print(parser.parse(line))
print(parse(line, local_env))
print(parse(line, local_env, None))

View file

@ -199,6 +199,13 @@ from itertools import islice
from pathlib import Path
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
@ -209,11 +216,6 @@ report_lock = threading.Lock()
log_format = "%(levelname)s %(name)s::%(module)s.%(funcName)s():%(lineno)d: %(message)s"
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
# for. Don't use it when invoking other components of the build system
# 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:
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:
sys.stderr.write(
"Failed processing %s\n" % self.testcase.yamlfile)