aboutsummaryrefslogtreecommitdiff
path: root/lib/python/qmk/info.py
diff options
context:
space:
mode:
authorZach White <skullydazed@gmail.com>2021-01-09 13:34:14 -0800
committerGitHub <noreply@github.com>2021-01-09 13:34:14 -0800
commit962bc8d9dd413690dbeadeaac971a5389697210f (patch)
tree02e7c5ebe87f466103901d72740fbf25c9d19a30 /lib/python/qmk/info.py
parentc550047ba68bd633d35b10d545ff240cf1fc9786 (diff)
downloadqmk_firmware-962bc8d9dd413690dbeadeaac971a5389697210f.tar.gz
qmk_firmware-962bc8d9dd413690dbeadeaac971a5389697210f.zip
Use the schema to eliminate custom code (#11108)
* use the schema to eliminate custom code * Update docs/reference_info_json.md Co-authored-by: Ryan <fauxpark@gmail.com> * make flake8 happy * bugfix * do not overwrite make vars from json Co-authored-by: Ryan <fauxpark@gmail.com>
Diffstat (limited to 'lib/python/qmk/info.py')
-rw-r--r--lib/python/qmk/info.py60
1 files changed, 29 insertions, 31 deletions
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py
index 28c281a4b..0ea5136a9 100644
--- a/lib/python/qmk/info.py
+++ b/lib/python/qmk/info.py
@@ -1,6 +1,7 @@
1"""Functions that help us generate and use info.json files. 1"""Functions that help us generate and use info.json files.
2""" 2"""
3import json 3import json
4from collections.abc import Mapping
4from glob import glob 5from glob import glob
5from pathlib import Path 6from pathlib import Path
6 7
@@ -140,6 +141,8 @@ def _json_load(json_file):
140 141
141def _jsonschema(schema_name): 142def _jsonschema(schema_name):
142 """Read a jsonschema file from disk. 143 """Read a jsonschema file from disk.
144
145 FIXME(skullydazed/anyone): Refactor to make this a public function.
143 """ 146 """
144 schema_path = Path(f'data/schemas/{schema_name}.jsonschema') 147 schema_path = Path(f'data/schemas/{schema_name}.jsonschema')
145 148
@@ -638,49 +641,44 @@ def unknown_processor_rules(info_data, rules):
638 return info_data 641 return info_data
639 642
640 643
644def deep_update(origdict, newdict):
645 """Update a dictionary in place, recursing to do a deep copy.
646 """
647 for key, value in newdict.items():
648 if isinstance(value, Mapping):
649 origdict[key] = deep_update(origdict.get(key, {}), value)
650
651 else:
652 origdict[key] = value
653
654 return origdict
655
656
641def merge_info_jsons(keyboard, info_data): 657def merge_info_jsons(keyboard, info_data):
642 """Return a merged copy of all the info.json files for a keyboard. 658 """Return a merged copy of all the info.json files for a keyboard.
643 """ 659 """
644 for info_file in find_info_json(keyboard): 660 for info_file in find_info_json(keyboard):
645 # Load and validate the JSON data 661 # Load and validate the JSON data
662 new_info_data = _json_load(info_file)
663
664 if not isinstance(new_info_data, dict):
665 _log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),))
666 continue
667
646 try: 668 try:
647 new_info_data = _json_load(info_file)
648 keyboard_validate(new_info_data) 669 keyboard_validate(new_info_data)
649
650 except jsonschema.ValidationError as e: 670 except jsonschema.ValidationError as e:
651 json_path = '.'.join([str(p) for p in e.absolute_path]) 671 json_path = '.'.join([str(p) for p in e.absolute_path])
652 cli.log.error('Invalid info.json data: %s: %s: %s', info_file, json_path, e.message) 672 cli.log.error('Not including data from file: %s', info_file)
673 cli.log.error('\t%s: %s', json_path, e.message)
653 continue 674 continue
654 675
655 if not isinstance(new_info_data, dict): 676 # Mark the layouts as coming from json
656 _log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),)) 677 for layout in new_info_data.get('layouts', {}).values():
657 continue 678 layout['c_macro'] = False
658
659 # Copy whitelisted keys into `info_data`
660 for key in ('debounce', 'diode_direction', 'indicators', 'keyboard_name', 'manufacturer', 'identifier', 'url', 'maintainer', 'processor', 'bootloader', 'width', 'height'):
661 if key in new_info_data:
662 info_data[key] = new_info_data[key]
663
664 # Deep merge certain keys
665 # FIXME(skullydazed/anyone): this should be generalized more so that we can inteligently merge more than one level deep. It would be nice if we could filter on valid keys too. That may have to wait for a future where we use openapi or something.
666 for key in ('features', 'layout_aliases', 'led_matrix', 'matrix_pins', 'rgblight', 'usb'):
667 if key in new_info_data:
668 if key not in info_data:
669 info_data[key] = {}
670
671 info_data[key].update(new_info_data[key])
672
673 # Merge the layouts
674 if 'community_layouts' in new_info_data:
675 if 'community_layouts' in info_data:
676 for layout in new_info_data['community_layouts']:
677 if layout not in info_data['community_layouts']:
678 info_data['community_layouts'].append(layout)
679 else:
680 info_data['community_layouts'] = new_info_data['community_layouts']
681 679
682 if 'layouts' in new_info_data: 680 # Update info_data with the new data
683 _merge_layouts(info_data, new_info_data) 681 deep_update(info_data, new_info_data)
684 682
685 return info_data 683 return info_data
686 684