diff options
Diffstat (limited to 'lib/python/qmk/info.py')
| -rw-r--r-- | lib/python/qmk/info.py | 69 |
1 files changed, 4 insertions, 65 deletions
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py index 60d3a0132..e2350b7f7 100644 --- a/lib/python/qmk/info.py +++ b/lib/python/qmk/info.py | |||
| @@ -1,17 +1,15 @@ | |||
| 1 | """Functions that help us generate and use info.json files. | 1 | """Functions that help us generate and use info.json files. |
| 2 | """ | 2 | """ |
| 3 | import json | ||
| 4 | from collections.abc import Mapping | ||
| 5 | from glob import glob | 3 | from glob import glob |
| 6 | from pathlib import Path | 4 | from pathlib import Path |
| 7 | 5 | ||
| 8 | import hjson | ||
| 9 | import jsonschema | 6 | import jsonschema |
| 10 | from dotty_dict import dotty | 7 | from dotty_dict import dotty |
| 11 | from milc import cli | 8 | from milc import cli |
| 12 | 9 | ||
| 13 | from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS | 10 | from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS |
| 14 | from qmk.c_parse import find_layouts | 11 | from qmk.c_parse import find_layouts |
| 12 | from qmk.json_schema import deep_update, json_load, keyboard_validate, keyboard_api_validate | ||
| 15 | from qmk.keyboard import config_h, rules_mk | 13 | from qmk.keyboard import config_h, rules_mk |
| 16 | from qmk.keymap import list_keymaps | 14 | from qmk.keymap import list_keymaps |
| 17 | from qmk.makefile import parse_rules_mk_file | 15 | from qmk.makefile import parse_rules_mk_file |
| @@ -82,52 +80,6 @@ def info_json(keyboard): | |||
| 82 | return info_data | 80 | return info_data |
| 83 | 81 | ||
| 84 | 82 | ||
| 85 | def _json_load(json_file): | ||
| 86 | """Load a json file from disk. | ||
| 87 | |||
| 88 | Note: file must be a Path object. | ||
| 89 | """ | ||
| 90 | try: | ||
| 91 | return hjson.load(json_file.open(encoding='utf-8')) | ||
| 92 | |||
| 93 | except json.decoder.JSONDecodeError as e: | ||
| 94 | cli.log.error('Invalid JSON encountered attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e) | ||
| 95 | exit(1) | ||
| 96 | |||
| 97 | |||
| 98 | def _jsonschema(schema_name): | ||
| 99 | """Read a jsonschema file from disk. | ||
| 100 | |||
| 101 | FIXME(skullydazed/anyone): Refactor to make this a public function. | ||
| 102 | """ | ||
| 103 | schema_path = Path(f'data/schemas/{schema_name}.jsonschema') | ||
| 104 | |||
| 105 | if not schema_path.exists(): | ||
| 106 | schema_path = Path('data/schemas/false.jsonschema') | ||
| 107 | |||
| 108 | return _json_load(schema_path) | ||
| 109 | |||
| 110 | |||
| 111 | def keyboard_validate(data): | ||
| 112 | """Validates data against the keyboard jsonschema. | ||
| 113 | """ | ||
| 114 | schema = _jsonschema('keyboard') | ||
| 115 | validator = jsonschema.Draft7Validator(schema).validate | ||
| 116 | |||
| 117 | return validator(data) | ||
| 118 | |||
| 119 | |||
| 120 | def keyboard_api_validate(data): | ||
| 121 | """Validates data against the api_keyboard jsonschema. | ||
| 122 | """ | ||
| 123 | base = _jsonschema('keyboard') | ||
| 124 | relative = _jsonschema('api_keyboard') | ||
| 125 | resolver = jsonschema.RefResolver.from_schema(base) | ||
| 126 | validator = jsonschema.Draft7Validator(relative, resolver=resolver).validate | ||
| 127 | |||
| 128 | return validator(data) | ||
| 129 | |||
| 130 | |||
| 131 | def _extract_features(info_data, rules): | 83 | def _extract_features(info_data, rules): |
| 132 | """Find all the features enabled in rules.mk. | 84 | """Find all the features enabled in rules.mk. |
| 133 | """ | 85 | """ |
| @@ -258,7 +210,7 @@ def _extract_config_h(info_data): | |||
| 258 | 210 | ||
| 259 | # Pull in data from the json map | 211 | # Pull in data from the json map |
| 260 | dotty_info = dotty(info_data) | 212 | dotty_info = dotty(info_data) |
| 261 | info_config_map = _json_load(Path('data/mappings/info_config.json')) | 213 | info_config_map = json_load(Path('data/mappings/info_config.json')) |
| 262 | 214 | ||
| 263 | for config_key, info_dict in info_config_map.items(): | 215 | for config_key, info_dict in info_config_map.items(): |
| 264 | info_key = info_dict['info_key'] | 216 | info_key = info_dict['info_key'] |
| @@ -326,7 +278,7 @@ def _extract_rules_mk(info_data): | |||
| 326 | 278 | ||
| 327 | # Pull in data from the json map | 279 | # Pull in data from the json map |
| 328 | dotty_info = dotty(info_data) | 280 | dotty_info = dotty(info_data) |
| 329 | info_rules_map = _json_load(Path('data/mappings/info_rules.json')) | 281 | info_rules_map = json_load(Path('data/mappings/info_rules.json')) |
| 330 | 282 | ||
| 331 | for rules_key, info_dict in info_rules_map.items(): | 283 | for rules_key, info_dict in info_rules_map.items(): |
| 332 | info_key = info_dict['info_key'] | 284 | info_key = info_dict['info_key'] |
| @@ -516,25 +468,12 @@ def unknown_processor_rules(info_data, rules): | |||
| 516 | return info_data | 468 | return info_data |
| 517 | 469 | ||
| 518 | 470 | ||
| 519 | def deep_update(origdict, newdict): | ||
| 520 | """Update a dictionary in place, recursing to do a deep copy. | ||
| 521 | """ | ||
| 522 | for key, value in newdict.items(): | ||
| 523 | if isinstance(value, Mapping): | ||
| 524 | origdict[key] = deep_update(origdict.get(key, {}), value) | ||
| 525 | |||
| 526 | else: | ||
| 527 | origdict[key] = value | ||
| 528 | |||
| 529 | return origdict | ||
| 530 | |||
| 531 | |||
| 532 | def merge_info_jsons(keyboard, info_data): | 471 | def merge_info_jsons(keyboard, info_data): |
| 533 | """Return a merged copy of all the info.json files for a keyboard. | 472 | """Return a merged copy of all the info.json files for a keyboard. |
| 534 | """ | 473 | """ |
| 535 | for info_file in find_info_json(keyboard): | 474 | for info_file in find_info_json(keyboard): |
| 536 | # Load and validate the JSON data | 475 | # Load and validate the JSON data |
| 537 | new_info_data = _json_load(info_file) | 476 | new_info_data = json_load(info_file) |
| 538 | 477 | ||
| 539 | if not isinstance(new_info_data, dict): | 478 | if not isinstance(new_info_data, dict): |
| 540 | _log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),)) | 479 | _log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),)) |
