First pass at supporting keyboard overrides at all levels

This commit is contained in:
Zach White 2021-09-09 11:13:50 -07:00
parent 93387f8941
commit 3f9e745b71
13 changed files with 104 additions and 87 deletions

View file

@ -1,5 +1,6 @@
"""Functions that help us generate and use info.json files.
"""
import json
from glob import glob
from pathlib import Path
@ -7,7 +8,7 @@ import jsonschema
from dotty_dict import dotty
from milc import cli
from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS
from qmk.constants import CHIBIOS_PROCESSORS, KEYBOARD_OUTPUT_PREFIX, LUFA_PROCESSORS, VUSB_PROCESSORS
from qmk.c_parse import find_layouts
from qmk.json_schema import deep_update, json_load, validate
from qmk.keyboard import config_h, rules_mk
@ -25,7 +26,7 @@ def _valid_community_layout(layout):
return (Path('layouts/default') / layout).exists()
def info_json(keyboard):
def info_json(keyboard, *, overrides=None):
"""Generate the info.json data for a specific keyboard.
"""
cur_dir = Path('keyboards')
@ -59,11 +60,14 @@ def info_json(keyboard):
layout_json['c_macro'] = True
info_data['layouts'][layout_name] = layout_json
# Merge in the data from info.json, config.h, and rules.mk
# Merge in the data from info.json, config.h, rules.mk, and overrides
info_data = merge_info_jsons(keyboard, info_data)
info_data = _extract_rules_mk(info_data)
info_data = _extract_config_h(info_data)
if overrides:
info_data = merge_info_data(info_data, overrides)
# Ensure that we have matrix row and column counts
info_data = _matrix_size(info_data)
@ -102,6 +106,17 @@ def info_json(keyboard):
return info_data
def get_keyboard_overrides(keyboard):
"""Checks for keyboard_overrides.json in the keyboard build directory and returns them if it exists.
"""
keyboard_filesafe = keyboard.replace('/', '_')
keyboard_output = Path(f'{KEYBOARD_OUTPUT_PREFIX}{keyboard_filesafe}')
keyboard_overrides_file = keyboard_output / 'keyboard_overrides.json'
if keyboard_overrides_file.exists():
return json.load(keyboard_overrides_file.open('r', encoding='utf-8'))
def _extract_features(info_data, rules):
"""Find all the features enabled in rules.mk.
"""
@ -660,6 +675,38 @@ def unknown_processor_rules(info_data, rules):
return info_data
def merge_info_data(info_data, new_info_data):
"""Return a merged copy of info_data and new_info_data.
"""
if 'layout_aliases' in new_info_data:
info_data['layout_aliases'] = {**info_data.get('layout_aliases', {}), **new_info_data['layout_aliases']}
del new_info_data['layout_aliases']
for layout_name, layout in new_info_data.get('layouts', {}).items():
if layout_name in info_data.get('layout_aliases', {}):
_log_warning(info_data, f"info.json uses alias name {layout_name} instead of {info_data['layout_aliases'][layout_name]}")
layout_name = info_data['layout_aliases'][layout_name]
if layout_name in info_data['layouts']:
if len(info_data['layouts'][layout_name]['layout']) != len(layout['layout']):
msg = '%s: %s: Number of elements in info.json does not match! info.json:%s != %s:%s'
_log_error(info_data, msg % (info_data['keyboard_folder'], layout_name, len(layout['layout']), layout_name, len(info_data['layouts'][layout_name]['layout'])))
else:
for new_key, existing_key in zip(layout['layout'], info_data['layouts'][layout_name]['layout']):
existing_key.update(new_key)
else:
layout['c_macro'] = False
info_data['layouts'][layout_name] = layout
# Update info_data with the new data
if 'layouts' in new_info_data:
del new_info_data['layouts']
deep_update(info_data, new_info_data)
return info_data
def merge_info_jsons(keyboard, info_data):
"""Return a merged copy of all the info.json files for a keyboard.
"""
@ -680,31 +727,7 @@ def merge_info_jsons(keyboard, info_data):
continue
# Merge layout data in
if 'layout_aliases' in new_info_data:
info_data['layout_aliases'] = {**info_data.get('layout_aliases', {}), **new_info_data['layout_aliases']}
del new_info_data['layout_aliases']
for layout_name, layout in new_info_data.get('layouts', {}).items():
if layout_name in info_data.get('layout_aliases', {}):
_log_warning(info_data, f"info.json uses alias name {layout_name} instead of {info_data['layout_aliases'][layout_name]}")
layout_name = info_data['layout_aliases'][layout_name]
if layout_name in info_data['layouts']:
if len(info_data['layouts'][layout_name]['layout']) != len(layout['layout']):
msg = '%s: %s: Number of elements in info.json does not match! info.json:%s != %s:%s'
_log_error(info_data, msg % (info_data['keyboard_folder'], layout_name, len(layout['layout']), layout_name, len(info_data['layouts'][layout_name]['layout'])))
else:
for new_key, existing_key in zip(layout['layout'], info_data['layouts'][layout_name]['layout']):
existing_key.update(new_key)
else:
layout['c_macro'] = False
info_data['layouts'][layout_name] = layout
# Update info_data with the new data
if 'layouts' in new_info_data:
del new_info_data['layouts']
deep_update(info_data, new_info_data)
merge_info_data(info_data, new_info_data)
return info_data