Added simple linter for targets.json

pull/4215/head
Jimmy Brisson 2017-04-20 16:48:41 -05:00
parent 9b082fff55
commit ae2268490f
1 changed files with 140 additions and 0 deletions

140
tools/targets/lint.py Normal file
View File

@ -0,0 +1,140 @@
"""A linting utility for targets.json"""
from os.path import join, abspath, dirname
if __name__ == "__main__":
import sys
ROOT = abspath(join(dirname(__file__), "..", ".."))
sys.path.insert(0, ROOT)
from copy import copy
from yaml import dump
from tools.targets import Target, set_targets_json_location, TARGET_MAP
def must_have_keys(keys, dict):
for key in keys:
if key not in dict:
yield "%s not found, and is required" % key
def may_have_keys(keys, dict):
for key in dict.keys():
if key not in keys:
yield "%s found, and is not allowed" % key
MCU_REQUIRED_KEYS = ["release_versions", "supported_toolchains",
"default_lib", "public", "inherits"]
MCU_ALLOWED_KEYS = ["device_has", "core", "extra_labels", "features", "bootloader_supported", "device_name", "post_binary_hook", "default_toolchain"] + MCU_REQUIRED_KEYS
def check_mcu(mcu_json, strict=False):
"""Generate a list of problems with an mcu"""
if strict:
for err in must_have_keys(MCU_REQUIRED_KEYS, mcu_json):
yield err
for err in may_have_keys(MCU_ALLOWED_KEYS, mcu_json):
yield err
if 'public' in mcu_json and mcu_json['public']:
yield "public must be false"
if ("release_versions" in mcu_json and
"5" in mcu_json["release_versions"] and
"supported_toolchains" in mcu_json):
for tc in ["GCC_ARM", "ARM", "IAR"]:
if tc not in mcu_json["supported_toolchains"]:
yield ("%s not found in supported_toolchains, and is "
"required by mbed OS 5" % tc)
BOARD_REQUIRED_KEYS = ["inherits"]
BOARD_ALLOWED_KEYS = ["supported_form_factors", "is_disk_virtual", "detect_code", "device_name", "extra_labels", "public"] + BOARD_REQUIRED_KEYS
def check_board(board_json, strict=False):
if strict:
for err in must_have_keys(BOARD_REQUIRED_KEYS, board_json):
yield err
for err in may_have_keys(BOARD_ALLOWED_KEYS, board_json):
yield err
def add_if(dict, key, val):
if val:
dict[key] = val
def _split_boards(resolution_order, tgt):
mcus = []
boards = []
iterable = iter(resolution_order)
for name in iterable:
mcu_json = tgt.json_data[name]
if (len(list(check_mcu(mcu_json, True))) >
len(list(check_board(mcu_json, True)))):
boards.append(name)
else:
mcus.append(name)
break
mcus.extend(iterable)
mcus.reverse()
boards.reverse()
return mcus, boards
MCU_FORMAT_STRING = {1: "MCU (%s) ->",
2: "Family (%s) -> MCU (%s) ->",
3: "Family (%s) -> SubFamily (%s) -> MCU (%s) ->"}
BOARD_FORMAT_STRING = {1: "Board (%s)",
2: "Module (%s) -> Board (%s)"}
def _generate_hierarchy_string(mcus, boards):
global_errors = []
if len(mcus) < 1:
global_errors.append("No MCUS found in heirarchy")
mcus_string = "??? ->"
elif len(mcus) > 3:
global_errors.append("No name for targets: %s" % mcus[3:])
mcus_string = MCU_FORMAT_STRING[3] % tuple(mcus[:3])
for name in mcus[3:]:
mcus_string += " ??? (%s) ->" % name
else:
mcus_string = MCU_FORMAT_STRING[len(mcus)] % tuple(mcus)
if len(boards) < 1:
global_errors.append("no boards found in heirarchy")
boards_string = "???"
elif len(boards) > 2:
global_errors.append("no name for targets: %s" % boards[2:])
boards_string = BOARD_FORMAT_STRING[3] % tuple(boards[:2])
for name in boards[2:]:
boards_string += " ??? (%s)" % name
else:
boards_string = BOARD_FORMAT_STRING[len(boards)] % tuple(boards)
return mcus_string + " " + boards_string, global_errors
def check_hierarchy(tgt):
"""Atempts to assign labels to the heirarchy"""
resolution_order = copy(tgt.resolution_order_names[:-1])
mcus, boards = _split_boards(resolution_order, tgt)
target_errors = {}
hierachy_string, hierachy_errors = _generate_hierarchy_string(mcus, boards)
to_ret = {"hierarchy": hierachy_string}
add_if(to_ret, "hierachy errors", hierachy_errors)
for name in mcus[:-1]:
add_if(target_errors, name, list(check_mcu(tgt.json_data[name])))
if len(mcus) >= 1:
add_if(target_errors, mcus[-1],
list(check_mcu(tgt.json_data[mcus[-1]], True)))
for name in boards:
add_if(target_errors, name, list(check_board(tgt.json_data[name])))
if len(boards) >= 1:
add_if(target_errors, boards[-1],
list(check_board(tgt.json_data[boards[-1]], True)))
add_if(to_ret, "target errors", target_errors)
return to_ret
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("mcu", choices=TARGET_MAP.keys(), metavar="MCU")
options = parser.parse_args()
print dump(check_hierarchy(TARGET_MAP[options.mcu]), default_flow_style=False)
return 0
if __name__ == "__main__":
sys.exit(main())