Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
mbed-os/tools/targets/lint.py@0:8fdf9a60065b, 2018-10-10 (annotated)
- Committer:
- kadonotakashi
- Date:
- Wed Oct 10 00:33:53 2018 +0000
- Revision:
- 0:8fdf9a60065b
how to make mbed librry
Who changed what in which revision?
| User | Revision | Line number | New contents of line | 
|---|---|---|---|
| kadonotakashi | 0:8fdf9a60065b | 1 | """A linting utility for targets.json | 
| kadonotakashi | 0:8fdf9a60065b | 2 | |
| kadonotakashi | 0:8fdf9a60065b | 3 | This linting utility may be called as follows: | 
| kadonotakashi | 0:8fdf9a60065b | 4 | python <path-to>/lint.py targets TARGET [TARGET ...] | 
| kadonotakashi | 0:8fdf9a60065b | 5 | |
| kadonotakashi | 0:8fdf9a60065b | 6 | all targets will be linted | 
| kadonotakashi | 0:8fdf9a60065b | 7 | """ | 
| kadonotakashi | 0:8fdf9a60065b | 8 | |
| kadonotakashi | 0:8fdf9a60065b | 9 | # mbed SDK | 
| kadonotakashi | 0:8fdf9a60065b | 10 | # Copyright (c) 2017 ARM Limited | 
| kadonotakashi | 0:8fdf9a60065b | 11 | # | 
| kadonotakashi | 0:8fdf9a60065b | 12 | # Licensed under the Apache License, Version 2.0 (the "License"); | 
| kadonotakashi | 0:8fdf9a60065b | 13 | # you may not use this file except in compliance with the License. | 
| kadonotakashi | 0:8fdf9a60065b | 14 | # You may obtain a copy of the License at | 
| kadonotakashi | 0:8fdf9a60065b | 15 | # | 
| kadonotakashi | 0:8fdf9a60065b | 16 | # http://www.apache.org/licenses/LICENSE-2.0 | 
| kadonotakashi | 0:8fdf9a60065b | 17 | # | 
| kadonotakashi | 0:8fdf9a60065b | 18 | # Unless required by applicable law or agreed to in writing, software | 
| kadonotakashi | 0:8fdf9a60065b | 19 | # distributed under the License is distributed on an "AS IS" BASIS, | 
| kadonotakashi | 0:8fdf9a60065b | 20 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| kadonotakashi | 0:8fdf9a60065b | 21 | # See the License for the specific language governing permissions and | 
| kadonotakashi | 0:8fdf9a60065b | 22 | # limitations under the License. | 
| kadonotakashi | 0:8fdf9a60065b | 23 | |
| kadonotakashi | 0:8fdf9a60065b | 24 | from os.path import join, abspath, dirname | 
| kadonotakashi | 0:8fdf9a60065b | 25 | if __name__ == "__main__": | 
| kadonotakashi | 0:8fdf9a60065b | 26 | import sys | 
| kadonotakashi | 0:8fdf9a60065b | 27 | ROOT = abspath(join(dirname(__file__), "..", "..")) | 
| kadonotakashi | 0:8fdf9a60065b | 28 | sys.path.insert(0, ROOT) | 
| kadonotakashi | 0:8fdf9a60065b | 29 | from copy import copy | 
| kadonotakashi | 0:8fdf9a60065b | 30 | from yaml import dump_all | 
| kadonotakashi | 0:8fdf9a60065b | 31 | import argparse | 
| kadonotakashi | 0:8fdf9a60065b | 32 | |
| kadonotakashi | 0:8fdf9a60065b | 33 | from tools.targets import Target, set_targets_json_location, TARGET_MAP | 
| kadonotakashi | 0:8fdf9a60065b | 34 | |
| kadonotakashi | 0:8fdf9a60065b | 35 | def must_have_keys(keys, dict): | 
| kadonotakashi | 0:8fdf9a60065b | 36 | """Require keys in an MCU/Board | 
| kadonotakashi | 0:8fdf9a60065b | 37 | |
| kadonotakashi | 0:8fdf9a60065b | 38 | is a generator for errors | 
| kadonotakashi | 0:8fdf9a60065b | 39 | """ | 
| kadonotakashi | 0:8fdf9a60065b | 40 | for key in keys: | 
| kadonotakashi | 0:8fdf9a60065b | 41 | if key not in dict: | 
| kadonotakashi | 0:8fdf9a60065b | 42 | yield "%s not found, and is required" % key | 
| kadonotakashi | 0:8fdf9a60065b | 43 | |
| kadonotakashi | 0:8fdf9a60065b | 44 | def may_have_keys(keys, dict): | 
| kadonotakashi | 0:8fdf9a60065b | 45 | """Disable all other keys in an MCU/Board | 
| kadonotakashi | 0:8fdf9a60065b | 46 | |
| kadonotakashi | 0:8fdf9a60065b | 47 | is a generator for errors | 
| kadonotakashi | 0:8fdf9a60065b | 48 | """ | 
| kadonotakashi | 0:8fdf9a60065b | 49 | for key in dict.keys(): | 
| kadonotakashi | 0:8fdf9a60065b | 50 | if key not in keys: | 
| kadonotakashi | 0:8fdf9a60065b | 51 | yield "%s found, and is not allowed" % key | 
| kadonotakashi | 0:8fdf9a60065b | 52 | |
| kadonotakashi | 0:8fdf9a60065b | 53 | def check_extra_labels(dict): | 
| kadonotakashi | 0:8fdf9a60065b | 54 | """Check that extra_labels does not contain any Target names | 
| kadonotakashi | 0:8fdf9a60065b | 55 | |
| kadonotakashi | 0:8fdf9a60065b | 56 | is a generator for errors | 
| kadonotakashi | 0:8fdf9a60065b | 57 | """ | 
| kadonotakashi | 0:8fdf9a60065b | 58 | for label in (dict.get("extra_labels", []) + | 
| kadonotakashi | 0:8fdf9a60065b | 59 | dict.get("extra_labels_add", [])): | 
| kadonotakashi | 0:8fdf9a60065b | 60 | if label in Target.get_json_target_data(): | 
| kadonotakashi | 0:8fdf9a60065b | 61 | yield "%s is not allowed in extra_labels" % label | 
| kadonotakashi | 0:8fdf9a60065b | 62 | |
| kadonotakashi | 0:8fdf9a60065b | 63 | def check_release_version(dict): | 
| kadonotakashi | 0:8fdf9a60065b | 64 | """Verify that release version 5 is combined with support for all toolcahins | 
| kadonotakashi | 0:8fdf9a60065b | 65 | |
| kadonotakashi | 0:8fdf9a60065b | 66 | is a generator for errors | 
| kadonotakashi | 0:8fdf9a60065b | 67 | """ | 
| kadonotakashi | 0:8fdf9a60065b | 68 | if ("release_versions" in dict and | 
| kadonotakashi | 0:8fdf9a60065b | 69 | "5" in dict["release_versions"] and | 
| kadonotakashi | 0:8fdf9a60065b | 70 | "supported_toolchains" in dict): | 
| kadonotakashi | 0:8fdf9a60065b | 71 | for toolc in ["GCC_ARM", "ARM", "IAR"]: | 
| kadonotakashi | 0:8fdf9a60065b | 72 | if toolc not in dict["supported_toolchains"]: | 
| kadonotakashi | 0:8fdf9a60065b | 73 | yield ("%s not found in supported_toolchains, and is " | 
| kadonotakashi | 0:8fdf9a60065b | 74 | "required by mbed OS 5" % toolc) | 
| kadonotakashi | 0:8fdf9a60065b | 75 | |
| kadonotakashi | 0:8fdf9a60065b | 76 | def check_inherits(dict): | 
| kadonotakashi | 0:8fdf9a60065b | 77 | if ("inherits" in dict and len(dict["inherits"]) > 1): | 
| kadonotakashi | 0:8fdf9a60065b | 78 | yield "multiple inheritance is forbidden" | 
| kadonotakashi | 0:8fdf9a60065b | 79 | |
| kadonotakashi | 0:8fdf9a60065b | 80 | DEVICE_HAS_ALLOWED = ["ANALOGIN", "ANALOGOUT", "CAN", "ETHERNET", "EMAC", | 
| kadonotakashi | 0:8fdf9a60065b | 81 | "FLASH", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", | 
| kadonotakashi | 0:8fdf9a60065b | 82 | "LPTICKER", "PORTIN", "PORTINOUT", "PORTOUT", | 
| kadonotakashi | 0:8fdf9a60065b | 83 | "PWMOUT", "RTC", "TRNG","SERIAL", "SERIAL_ASYNCH", | 
| kadonotakashi | 0:8fdf9a60065b | 84 | "SERIAL_FC", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", | 
| kadonotakashi | 0:8fdf9a60065b | 85 | "STORAGE", "SYSTICK_CLK_OFF_DURING_SLEEP"] | 
| kadonotakashi | 0:8fdf9a60065b | 86 | def check_device_has(dict): | 
| kadonotakashi | 0:8fdf9a60065b | 87 | for name in dict.get("device_has", []): | 
| kadonotakashi | 0:8fdf9a60065b | 88 | if name not in DEVICE_HAS_ALLOWED: | 
| kadonotakashi | 0:8fdf9a60065b | 89 | yield "%s is not allowed in device_has" % name | 
| kadonotakashi | 0:8fdf9a60065b | 90 | |
| kadonotakashi | 0:8fdf9a60065b | 91 | MCU_REQUIRED_KEYS = ["release_versions", "supported_toolchains", | 
| kadonotakashi | 0:8fdf9a60065b | 92 | "default_lib", "public", "inherits", "device_has"] | 
| kadonotakashi | 0:8fdf9a60065b | 93 | MCU_ALLOWED_KEYS = ["device_has_add", "device_has_remove", "core", | 
| kadonotakashi | 0:8fdf9a60065b | 94 | "extra_labels", "features", "features_add", | 
| kadonotakashi | 0:8fdf9a60065b | 95 | "features_remove", "bootloader_supported", "device_name", | 
| kadonotakashi | 0:8fdf9a60065b | 96 | "post_binary_hook", "default_toolchain", "config", | 
| kadonotakashi | 0:8fdf9a60065b | 97 | "extra_labels_add", "extra_labels_remove", | 
| kadonotakashi | 0:8fdf9a60065b | 98 | "target_overrides"] + MCU_REQUIRED_KEYS | 
| kadonotakashi | 0:8fdf9a60065b | 99 | def check_mcu(mcu_json, strict=False): | 
| kadonotakashi | 0:8fdf9a60065b | 100 | """Generate a list of problems with an MCU | 
| kadonotakashi | 0:8fdf9a60065b | 101 | |
| kadonotakashi | 0:8fdf9a60065b | 102 | :param: mcu_json the MCU's dict to check | 
| kadonotakashi | 0:8fdf9a60065b | 103 | :param: strict enforce required keys | 
| kadonotakashi | 0:8fdf9a60065b | 104 | """ | 
| kadonotakashi | 0:8fdf9a60065b | 105 | errors = list(may_have_keys(MCU_ALLOWED_KEYS, mcu_json)) | 
| kadonotakashi | 0:8fdf9a60065b | 106 | if strict: | 
| kadonotakashi | 0:8fdf9a60065b | 107 | errors.extend(must_have_keys(MCU_REQUIRED_KEYS, mcu_json)) | 
| kadonotakashi | 0:8fdf9a60065b | 108 | errors.extend(check_extra_labels(mcu_json)) | 
| kadonotakashi | 0:8fdf9a60065b | 109 | errors.extend(check_release_version(mcu_json)) | 
| kadonotakashi | 0:8fdf9a60065b | 110 | errors.extend(check_inherits(mcu_json)) | 
| kadonotakashi | 0:8fdf9a60065b | 111 | errors.extend(check_device_has(mcu_json)) | 
| kadonotakashi | 0:8fdf9a60065b | 112 | if 'public' in mcu_json and mcu_json['public']: | 
| kadonotakashi | 0:8fdf9a60065b | 113 | errors.append("public must be false") | 
| kadonotakashi | 0:8fdf9a60065b | 114 | return errors | 
| kadonotakashi | 0:8fdf9a60065b | 115 | |
| kadonotakashi | 0:8fdf9a60065b | 116 | BOARD_REQUIRED_KEYS = ["inherits"] | 
| kadonotakashi | 0:8fdf9a60065b | 117 | BOARD_ALLOWED_KEYS = ["supported_form_factors", "is_disk_virtual", | 
| kadonotakashi | 0:8fdf9a60065b | 118 | "detect_code", "extra_labels", "extra_labels_add", | 
| kadonotakashi | 0:8fdf9a60065b | 119 | "extra_labels_remove", "public", "config", | 
| kadonotakashi | 0:8fdf9a60065b | 120 | "forced_reset_timeout", "target_overrides"] + BOARD_REQUIRED_KEYS | 
| kadonotakashi | 0:8fdf9a60065b | 121 | def check_board(board_json, strict=False): | 
| kadonotakashi | 0:8fdf9a60065b | 122 | """Generate a list of problems with an board | 
| kadonotakashi | 0:8fdf9a60065b | 123 | |
| kadonotakashi | 0:8fdf9a60065b | 124 | :param: board_json the mcus dict to check | 
| kadonotakashi | 0:8fdf9a60065b | 125 | :param: strict enforce required keys | 
| kadonotakashi | 0:8fdf9a60065b | 126 | """ | 
| kadonotakashi | 0:8fdf9a60065b | 127 | errors = list(may_have_keys(BOARD_ALLOWED_KEYS, board_json)) | 
| kadonotakashi | 0:8fdf9a60065b | 128 | if strict: | 
| kadonotakashi | 0:8fdf9a60065b | 129 | errors.extend(must_have_keys(BOARD_REQUIRED_KEYS, board_json)) | 
| kadonotakashi | 0:8fdf9a60065b | 130 | errors.extend(check_extra_labels(board_json)) | 
| kadonotakashi | 0:8fdf9a60065b | 131 | errors.extend(check_inherits(board_json)) | 
| kadonotakashi | 0:8fdf9a60065b | 132 | return errors | 
| kadonotakashi | 0:8fdf9a60065b | 133 | |
| kadonotakashi | 0:8fdf9a60065b | 134 | def add_if(dict, key, val): | 
| kadonotakashi | 0:8fdf9a60065b | 135 | """Add a value to a dict if it's non-empty""" | 
| kadonotakashi | 0:8fdf9a60065b | 136 | if val: | 
| kadonotakashi | 0:8fdf9a60065b | 137 | dict[key] = val | 
| kadonotakashi | 0:8fdf9a60065b | 138 | |
| kadonotakashi | 0:8fdf9a60065b | 139 | def _split_boards(resolution_order, tgt): | 
| kadonotakashi | 0:8fdf9a60065b | 140 | """Split the resolution order between boards and mcus""" | 
| kadonotakashi | 0:8fdf9a60065b | 141 | mcus = [] | 
| kadonotakashi | 0:8fdf9a60065b | 142 | boards = [] | 
| kadonotakashi | 0:8fdf9a60065b | 143 | iterable = iter(resolution_order) | 
| kadonotakashi | 0:8fdf9a60065b | 144 | for name in iterable: | 
| kadonotakashi | 0:8fdf9a60065b | 145 | mcu_json = tgt.json_data[name] | 
| kadonotakashi | 0:8fdf9a60065b | 146 | if (len(list(check_mcu(mcu_json, True))) > | 
| kadonotakashi | 0:8fdf9a60065b | 147 | len(list(check_board(mcu_json, True)))): | 
| kadonotakashi | 0:8fdf9a60065b | 148 | boards.append(name) | 
| kadonotakashi | 0:8fdf9a60065b | 149 | else: | 
| kadonotakashi | 0:8fdf9a60065b | 150 | mcus.append(name) | 
| kadonotakashi | 0:8fdf9a60065b | 151 | break | 
| kadonotakashi | 0:8fdf9a60065b | 152 | mcus.extend(iterable) | 
| kadonotakashi | 0:8fdf9a60065b | 153 | mcus.reverse() | 
| kadonotakashi | 0:8fdf9a60065b | 154 | boards.reverse() | 
| kadonotakashi | 0:8fdf9a60065b | 155 | return mcus, boards | 
| kadonotakashi | 0:8fdf9a60065b | 156 | |
| kadonotakashi | 0:8fdf9a60065b | 157 | |
| kadonotakashi | 0:8fdf9a60065b | 158 | MCU_FORMAT_STRING = {1: "MCU (%s) ->", | 
| kadonotakashi | 0:8fdf9a60065b | 159 | 2: "Family (%s) -> MCU (%s) ->", | 
| kadonotakashi | 0:8fdf9a60065b | 160 | 3: "Family (%s) -> SubFamily (%s) -> MCU (%s) ->"} | 
| kadonotakashi | 0:8fdf9a60065b | 161 | BOARD_FORMAT_STRING = {1: "Board (%s)", | 
| kadonotakashi | 0:8fdf9a60065b | 162 | 2: "Module (%s) -> Board (%s)"} | 
| kadonotakashi | 0:8fdf9a60065b | 163 | def _generate_hierarchy_string(mcus, boards): | 
| kadonotakashi | 0:8fdf9a60065b | 164 | global_errors = [] | 
| kadonotakashi | 0:8fdf9a60065b | 165 | if len(mcus) < 1: | 
| kadonotakashi | 0:8fdf9a60065b | 166 | global_errors.append("No MCUS found in hierarchy") | 
| kadonotakashi | 0:8fdf9a60065b | 167 | mcus_string = "??? ->" | 
| kadonotakashi | 0:8fdf9a60065b | 168 | elif len(mcus) > 3: | 
| kadonotakashi | 0:8fdf9a60065b | 169 | global_errors.append("No name for targets %s" % ", ".join(mcus[3:])) | 
| kadonotakashi | 0:8fdf9a60065b | 170 | mcus_string = MCU_FORMAT_STRING[3] % tuple(mcus[:3]) | 
| kadonotakashi | 0:8fdf9a60065b | 171 | for name in mcus[3:]: | 
| kadonotakashi | 0:8fdf9a60065b | 172 | mcus_string += " ??? (%s) ->" % name | 
| kadonotakashi | 0:8fdf9a60065b | 173 | else: | 
| kadonotakashi | 0:8fdf9a60065b | 174 | mcus_string = MCU_FORMAT_STRING[len(mcus)] % tuple(mcus) | 
| kadonotakashi | 0:8fdf9a60065b | 175 | |
| kadonotakashi | 0:8fdf9a60065b | 176 | if len(boards) < 1: | 
| kadonotakashi | 0:8fdf9a60065b | 177 | global_errors.append("no boards found in hierarchy") | 
| kadonotakashi | 0:8fdf9a60065b | 178 | boards_string = "???" | 
| kadonotakashi | 0:8fdf9a60065b | 179 | elif len(boards) > 2: | 
| kadonotakashi | 0:8fdf9a60065b | 180 | global_errors.append("no name for targets %s" % ", ".join(boards[2:])) | 
| kadonotakashi | 0:8fdf9a60065b | 181 | boards_string = BOARD_FORMAT_STRING[2] % tuple(boards[:2]) | 
| kadonotakashi | 0:8fdf9a60065b | 182 | for name in boards[2:]: | 
| kadonotakashi | 0:8fdf9a60065b | 183 | boards_string += " -> ??? (%s)" % name | 
| kadonotakashi | 0:8fdf9a60065b | 184 | else: | 
| kadonotakashi | 0:8fdf9a60065b | 185 | boards_string = BOARD_FORMAT_STRING[len(boards)] % tuple(boards) | 
| kadonotakashi | 0:8fdf9a60065b | 186 | return mcus_string + " " + boards_string, global_errors | 
| kadonotakashi | 0:8fdf9a60065b | 187 | |
| kadonotakashi | 0:8fdf9a60065b | 188 | |
| kadonotakashi | 0:8fdf9a60065b | 189 | def check_hierarchy(tgt): | 
| kadonotakashi | 0:8fdf9a60065b | 190 | """Atempts to assign labels to the hierarchy""" | 
| kadonotakashi | 0:8fdf9a60065b | 191 | resolution_order = copy(tgt.resolution_order_names[:-1]) | 
| kadonotakashi | 0:8fdf9a60065b | 192 | mcus, boards = _split_boards(resolution_order, tgt) | 
| kadonotakashi | 0:8fdf9a60065b | 193 | |
| kadonotakashi | 0:8fdf9a60065b | 194 | target_errors = {} | 
| kadonotakashi | 0:8fdf9a60065b | 195 | hierachy_string, hierachy_errors = _generate_hierarchy_string(mcus, boards) | 
| kadonotakashi | 0:8fdf9a60065b | 196 | to_ret = {"hierarchy": hierachy_string} | 
| kadonotakashi | 0:8fdf9a60065b | 197 | add_if(to_ret, "hierarchy errors", hierachy_errors) | 
| kadonotakashi | 0:8fdf9a60065b | 198 | |
| kadonotakashi | 0:8fdf9a60065b | 199 | for name in mcus[:-1]: | 
| kadonotakashi | 0:8fdf9a60065b | 200 | add_if(target_errors, name, list(check_mcu(tgt.json_data[name]))) | 
| kadonotakashi | 0:8fdf9a60065b | 201 | if len(mcus) >= 1: | 
| kadonotakashi | 0:8fdf9a60065b | 202 | add_if(target_errors, mcus[-1], | 
| kadonotakashi | 0:8fdf9a60065b | 203 | list(check_mcu(tgt.json_data[mcus[-1]], True))) | 
| kadonotakashi | 0:8fdf9a60065b | 204 | for name in boards: | 
| kadonotakashi | 0:8fdf9a60065b | 205 | add_if(target_errors, name, list(check_board(tgt.json_data[name]))) | 
| kadonotakashi | 0:8fdf9a60065b | 206 | if len(boards) >= 1: | 
| kadonotakashi | 0:8fdf9a60065b | 207 | add_if(target_errors, boards[-1], | 
| kadonotakashi | 0:8fdf9a60065b | 208 | list(check_board(tgt.json_data[boards[-1]], True))) | 
| kadonotakashi | 0:8fdf9a60065b | 209 | add_if(to_ret, "target errors", target_errors) | 
| kadonotakashi | 0:8fdf9a60065b | 210 | return to_ret | 
| kadonotakashi | 0:8fdf9a60065b | 211 | |
| kadonotakashi | 0:8fdf9a60065b | 212 | PARSER = argparse.ArgumentParser(prog="targets/lint.py") | 
| kadonotakashi | 0:8fdf9a60065b | 213 | SUBPARSERS = PARSER.add_subparsers(title="Commands") | 
| kadonotakashi | 0:8fdf9a60065b | 214 | |
| kadonotakashi | 0:8fdf9a60065b | 215 | def subcommand(name, *args, **kwargs): | 
| kadonotakashi | 0:8fdf9a60065b | 216 | def __subcommand(command): | 
| kadonotakashi | 0:8fdf9a60065b | 217 | kwargs['description'] = command.__doc__ | 
| kadonotakashi | 0:8fdf9a60065b | 218 | subparser = SUBPARSERS.add_parser(name, **kwargs) | 
| kadonotakashi | 0:8fdf9a60065b | 219 | for arg in args: | 
| kadonotakashi | 0:8fdf9a60065b | 220 | arg = dict(arg) | 
| kadonotakashi | 0:8fdf9a60065b | 221 | opt = arg['name'] | 
| kadonotakashi | 0:8fdf9a60065b | 222 | del arg['name'] | 
| kadonotakashi | 0:8fdf9a60065b | 223 | |
| kadonotakashi | 0:8fdf9a60065b | 224 | if isinstance(opt, basestring): | 
| kadonotakashi | 0:8fdf9a60065b | 225 | subparser.add_argument(opt, **arg) | 
| kadonotakashi | 0:8fdf9a60065b | 226 | else: | 
| kadonotakashi | 0:8fdf9a60065b | 227 | subparser.add_argument(*opt, **arg) | 
| kadonotakashi | 0:8fdf9a60065b | 228 | |
| kadonotakashi | 0:8fdf9a60065b | 229 | def _thunk(parsed_args): | 
| kadonotakashi | 0:8fdf9a60065b | 230 | argv = [arg['dest'] if 'dest' in arg else arg['name'] | 
| kadonotakashi | 0:8fdf9a60065b | 231 | for arg in args] | 
| kadonotakashi | 0:8fdf9a60065b | 232 | argv = [(arg if isinstance(arg, basestring) | 
| kadonotakashi | 0:8fdf9a60065b | 233 | else arg[-1]).strip('-').replace('-', '_') | 
| kadonotakashi | 0:8fdf9a60065b | 234 | for arg in argv] | 
| kadonotakashi | 0:8fdf9a60065b | 235 | argv = {arg: vars(parsed_args)[arg] for arg in argv | 
| kadonotakashi | 0:8fdf9a60065b | 236 | if vars(parsed_args)[arg] is not None} | 
| kadonotakashi | 0:8fdf9a60065b | 237 | |
| kadonotakashi | 0:8fdf9a60065b | 238 | return command(**argv) | 
| kadonotakashi | 0:8fdf9a60065b | 239 | |
| kadonotakashi | 0:8fdf9a60065b | 240 | subparser.set_defaults(command=_thunk) | 
| kadonotakashi | 0:8fdf9a60065b | 241 | return command | 
| kadonotakashi | 0:8fdf9a60065b | 242 | return __subcommand | 
| kadonotakashi | 0:8fdf9a60065b | 243 | |
| kadonotakashi | 0:8fdf9a60065b | 244 | @subcommand("targets", | 
| kadonotakashi | 0:8fdf9a60065b | 245 | dict(name="mcus", nargs="+", metavar="MCU", | 
| kadonotakashi | 0:8fdf9a60065b | 246 | choices=TARGET_MAP.keys(), type=str.upper)) | 
| kadonotakashi | 0:8fdf9a60065b | 247 | def targets_cmd(mcus=[]): | 
| kadonotakashi | 0:8fdf9a60065b | 248 | """Find and print errors about specific targets""" | 
| kadonotakashi | 0:8fdf9a60065b | 249 | print dump_all([check_hierarchy(TARGET_MAP[m]) for m in mcus], | 
| kadonotakashi | 0:8fdf9a60065b | 250 | default_flow_style=False) | 
| kadonotakashi | 0:8fdf9a60065b | 251 | |
| kadonotakashi | 0:8fdf9a60065b | 252 | @subcommand("all-targets") | 
| kadonotakashi | 0:8fdf9a60065b | 253 | def all_targets_cmd(): | 
| kadonotakashi | 0:8fdf9a60065b | 254 | """Print all errors about all parts""" | 
| kadonotakashi | 0:8fdf9a60065b | 255 | print dump_all([check_hierarchy(m) for m in TARGET_MAP.values()], | 
| kadonotakashi | 0:8fdf9a60065b | 256 | default_flow_style=False) | 
| kadonotakashi | 0:8fdf9a60065b | 257 | |
| kadonotakashi | 0:8fdf9a60065b | 258 | @subcommand("orphans") | 
| kadonotakashi | 0:8fdf9a60065b | 259 | def orphans_cmd(): | 
| kadonotakashi | 0:8fdf9a60065b | 260 | """Find and print all orphan targets""" | 
| kadonotakashi | 0:8fdf9a60065b | 261 | orphans = Target.get_json_target_data().keys() | 
| kadonotakashi | 0:8fdf9a60065b | 262 | for tgt in TARGET_MAP.values(): | 
| kadonotakashi | 0:8fdf9a60065b | 263 | for name in tgt.resolution_order_names: | 
| kadonotakashi | 0:8fdf9a60065b | 264 | if name in orphans: | 
| kadonotakashi | 0:8fdf9a60065b | 265 | orphans.remove(name) | 
| kadonotakashi | 0:8fdf9a60065b | 266 | if orphans: | 
| kadonotakashi | 0:8fdf9a60065b | 267 | print dump_all([orphans], default_flow_style=False) | 
| kadonotakashi | 0:8fdf9a60065b | 268 | return len(orphans) | 
| kadonotakashi | 0:8fdf9a60065b | 269 | |
| kadonotakashi | 0:8fdf9a60065b | 270 | def main(): | 
| kadonotakashi | 0:8fdf9a60065b | 271 | """entry point""" | 
| kadonotakashi | 0:8fdf9a60065b | 272 | options = PARSER.parse_args() | 
| kadonotakashi | 0:8fdf9a60065b | 273 | return options.command(options) | 
| kadonotakashi | 0:8fdf9a60065b | 274 | |
| kadonotakashi | 0:8fdf9a60065b | 275 | if __name__ == "__main__": | 
| kadonotakashi | 0:8fdf9a60065b | 276 | sys.exit(main()) | 
| kadonotakashi | 0:8fdf9a60065b | 277 |