|
| 1 | +"""A linting utility for targets.json""" |
| 2 | + |
| 3 | +from os.path import join, abspath, dirname |
| 4 | +if __name__ == "__main__": |
| 5 | + import sys |
| 6 | + ROOT = abspath(join(dirname(__file__), "..", "..")) |
| 7 | + sys.path.insert(0, ROOT) |
| 8 | +from copy import copy |
| 9 | +from yaml import dump |
| 10 | +from tools.targets import Target, set_targets_json_location, TARGET_MAP |
| 11 | + |
| 12 | +def must_have_keys(keys, dict): |
| 13 | + for key in keys: |
| 14 | + if key not in dict: |
| 15 | + yield "%s not found, and is required" % key |
| 16 | + |
| 17 | +def may_have_keys(keys, dict): |
| 18 | + for key in dict.keys(): |
| 19 | + if key not in keys: |
| 20 | + yield "%s found, and is not allowed" % key |
| 21 | + |
| 22 | + |
| 23 | +MCU_REQUIRED_KEYS = ["release_versions", "supported_toolchains", |
| 24 | + "default_lib", "public", "inherits"] |
| 25 | +MCU_ALLOWED_KEYS = ["device_has", "core", "extra_labels", "features", "bootloader_supported", "device_name", "post_binary_hook", "default_toolchain"] + MCU_REQUIRED_KEYS |
| 26 | +def check_mcu(mcu_json, strict=False): |
| 27 | + """Generate a list of problems with an mcu""" |
| 28 | + if strict: |
| 29 | + for err in must_have_keys(MCU_REQUIRED_KEYS, mcu_json): |
| 30 | + yield err |
| 31 | + for err in may_have_keys(MCU_ALLOWED_KEYS, mcu_json): |
| 32 | + yield err |
| 33 | + if 'public' in mcu_json and mcu_json['public']: |
| 34 | + yield "public must be false" |
| 35 | + if ("release_versions" in mcu_json and |
| 36 | + "5" in mcu_json["release_versions"] and |
| 37 | + "supported_toolchains" in mcu_json): |
| 38 | + for tc in ["GCC_ARM", "ARM", "IAR"]: |
| 39 | + if tc not in mcu_json["supported_toolchains"]: |
| 40 | + yield ("%s not found in supported_toolchains, and is " |
| 41 | + "required by mbed OS 5" % tc) |
| 42 | + |
| 43 | +BOARD_REQUIRED_KEYS = ["inherits"] |
| 44 | +BOARD_ALLOWED_KEYS = ["supported_form_factors", "is_disk_virtual", "detect_code", "device_name", "extra_labels", "public"] + BOARD_REQUIRED_KEYS |
| 45 | +def check_board(board_json, strict=False): |
| 46 | + if strict: |
| 47 | + for err in must_have_keys(BOARD_REQUIRED_KEYS, board_json): |
| 48 | + yield err |
| 49 | + for err in may_have_keys(BOARD_ALLOWED_KEYS, board_json): |
| 50 | + yield err |
| 51 | + |
| 52 | + |
| 53 | +def add_if(dict, key, val): |
| 54 | + if val: |
| 55 | + dict[key] = val |
| 56 | + |
| 57 | +def _split_boards(resolution_order, tgt): |
| 58 | + mcus = [] |
| 59 | + boards = [] |
| 60 | + iterable = iter(resolution_order) |
| 61 | + for name in iterable: |
| 62 | + mcu_json = tgt.json_data[name] |
| 63 | + if (len(list(check_mcu(mcu_json, True))) > |
| 64 | + len(list(check_board(mcu_json, True)))): |
| 65 | + boards.append(name) |
| 66 | + else: |
| 67 | + mcus.append(name) |
| 68 | + break |
| 69 | + mcus.extend(iterable) |
| 70 | + mcus.reverse() |
| 71 | + boards.reverse() |
| 72 | + return mcus, boards |
| 73 | + |
| 74 | + |
| 75 | +MCU_FORMAT_STRING = {1: "MCU (%s) ->", |
| 76 | + 2: "Family (%s) -> MCU (%s) ->", |
| 77 | + 3: "Family (%s) -> SubFamily (%s) -> MCU (%s) ->"} |
| 78 | +BOARD_FORMAT_STRING = {1: "Board (%s)", |
| 79 | + 2: "Module (%s) -> Board (%s)"} |
| 80 | +def _generate_hierarchy_string(mcus, boards): |
| 81 | + global_errors = [] |
| 82 | + if len(mcus) < 1: |
| 83 | + global_errors.append("No MCUS found in heirarchy") |
| 84 | + mcus_string = "??? ->" |
| 85 | + elif len(mcus) > 3: |
| 86 | + global_errors.append("No name for targets: %s" % mcus[3:]) |
| 87 | + mcus_string = MCU_FORMAT_STRING[3] % tuple(mcus[:3]) |
| 88 | + for name in mcus[3:]: |
| 89 | + mcus_string += " ??? (%s) ->" % name |
| 90 | + else: |
| 91 | + mcus_string = MCU_FORMAT_STRING[len(mcus)] % tuple(mcus) |
| 92 | + |
| 93 | + if len(boards) < 1: |
| 94 | + global_errors.append("no boards found in heirarchy") |
| 95 | + boards_string = "???" |
| 96 | + elif len(boards) > 2: |
| 97 | + global_errors.append("no name for targets: %s" % boards[2:]) |
| 98 | + boards_string = BOARD_FORMAT_STRING[3] % tuple(boards[:2]) |
| 99 | + for name in boards[2:]: |
| 100 | + boards_string += " ??? (%s)" % name |
| 101 | + else: |
| 102 | + boards_string = BOARD_FORMAT_STRING[len(boards)] % tuple(boards) |
| 103 | + return mcus_string + " " + boards_string, global_errors |
| 104 | + |
| 105 | + |
| 106 | +def check_hierarchy(tgt): |
| 107 | + """Atempts to assign labels to the heirarchy""" |
| 108 | + resolution_order = copy(tgt.resolution_order_names[:-1]) |
| 109 | + mcus, boards = _split_boards(resolution_order, tgt) |
| 110 | + |
| 111 | + target_errors = {} |
| 112 | + hierachy_string, hierachy_errors = _generate_hierarchy_string(mcus, boards) |
| 113 | + to_ret = {"hierarchy": hierachy_string} |
| 114 | + add_if(to_ret, "hierachy errors", hierachy_errors) |
| 115 | + |
| 116 | + for name in mcus[:-1]: |
| 117 | + add_if(target_errors, name, list(check_mcu(tgt.json_data[name]))) |
| 118 | + if len(mcus) >= 1: |
| 119 | + add_if(target_errors, mcus[-1], |
| 120 | + list(check_mcu(tgt.json_data[mcus[-1]], True))) |
| 121 | + for name in boards: |
| 122 | + add_if(target_errors, name, list(check_board(tgt.json_data[name]))) |
| 123 | + if len(boards) >= 1: |
| 124 | + add_if(target_errors, boards[-1], |
| 125 | + list(check_board(tgt.json_data[boards[-1]], True))) |
| 126 | + add_if(to_ret, "target errors", target_errors) |
| 127 | + return to_ret |
| 128 | + |
| 129 | + |
| 130 | +def main(): |
| 131 | + import argparse |
| 132 | + parser = argparse.ArgumentParser() |
| 133 | + parser.add_argument("mcu", choices=TARGET_MAP.keys(), metavar="MCU") |
| 134 | + options = parser.parse_args() |
| 135 | + print dump(check_hierarchy(TARGET_MAP[options.mcu]), default_flow_style=False) |
| 136 | + return 0 |
| 137 | + |
| 138 | +if __name__ == "__main__": |
| 139 | + sys.exit(main()) |
| 140 | + |
0 commit comments