From e4f4ceaf3f2e3d25fb282273a81f9b58790fc427 Mon Sep 17 00:00:00 2001 From: lokher Date: Wed, 26 Apr 2023 16:32:15 +0800 Subject: merge upstream 713427c --- lib/python/qmk/info.py | 80 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 20 deletions(-) (limited to 'lib/python/qmk/info.py') diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py index 7e588b5182..b7ee055eef 100644 --- a/lib/python/qmk/info.py +++ b/lib/python/qmk/info.py @@ -1,16 +1,16 @@ """Functions that help us generate and use info.json files. """ +import re from pathlib import Path - import jsonschema from dotty_dict import dotty + from milc import cli from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS from qmk.c_parse import find_layouts, parse_config_h_file, find_led_config from qmk.json_schema import deep_update, json_load, validate from qmk.keyboard import config_h, rules_mk -from qmk.keymap import list_keymaps, locate_keymap from qmk.commands import parse_configurator_json from qmk.makefile import parse_rules_mk_file from qmk.math import compute @@ -18,15 +18,30 @@ from qmk.math import compute true_values = ['1', 'on', 'yes'] false_values = ['0', 'off', 'no'] -# TODO: reduce this list down -SAFE_LAYOUT_TOKENS = { - 'ansi', - 'iso', - 'wkl', - 'tkl', - 'preonic', - 'planck', -} + +def _keyboard_in_layout_name(keyboard, layout): + """Validate that a layout macro does not contain name of keyboard + """ + # TODO: reduce this list down + safe_layout_tokens = { + 'ansi', + 'iso', + 'jp', + 'jis', + 'ortho', + 'wkl', + 'tkl', + 'preonic', + 'planck', + } + + # Ignore tokens like 'split_3x7_4' or just '2x4' + layout = re.sub(r"_split_\d+x\d+_\d+", '', layout) + layout = re.sub(r"_\d+x\d+", '', layout) + + name_fragments = set(keyboard.split('/')) - safe_layout_tokens + + return any(fragment in layout for fragment in name_fragments) def _valid_community_layout(layout): @@ -53,18 +68,27 @@ def _validate(keyboard, info_data): community_layouts_names = list(map(lambda layout: f'LAYOUT_{layout}', community_layouts)) # Make sure we have at least one layout - if len(layouts) == 0: + if len(layouts) == 0 or all(not layout.get('json_layout', False) for layout in layouts.values()): _log_error(info_data, 'No LAYOUTs defined! Need at least one layout defined in info.json.') + # Warn if physical positions are offset (at least one key should be at x=0, and at least one key at y=0) + for layout_name, layout_data in layouts.items(): + offset_x = min([k['x'] for k in layout_data['layout']]) + if offset_x > 0: + _log_warning(info_data, f'Layout "{layout_name}" is offset on X axis by {offset_x}') + + offset_y = min([k['y'] for k in layout_data['layout']]) + if offset_y > 0: + _log_warning(info_data, f'Layout "{layout_name}" is offset on Y axis by {offset_y}') + # Providing only LAYOUT_all "because I define my layouts in a 3rd party tool" if len(layouts) == 1 and 'LAYOUT_all' in layouts: _log_warning(info_data, '"LAYOUT_all" should be "LAYOUT" unless additional layouts are provided.') # Extended layout name checks - ignoring community_layouts and "safe" values - name_fragments = set(keyboard.split('/')) - SAFE_LAYOUT_TOKENS potential_layouts = set(layouts.keys()) - set(community_layouts_names) for layout in potential_layouts: - if any(fragment in layout for fragment in name_fragments): + if _keyboard_in_layout_name(keyboard, layout): _log_warning(info_data, f'Layout "{layout}" should not contain name of keyboard.') # Filter out any non-existing community layouts @@ -99,10 +123,6 @@ def info_json(keyboard): 'maintainer': 'qmk', } - # Populate the list of JSON keymaps - for keymap in list_keymaps(keyboard, c=False, fullpath=True): - info_data['keymaps'][keymap.name] = {'url': f'https://raw.githubusercontent.com/qmk/qmk_firmware/master/{keymap}/keymap.json'} - # Populate layout data layouts, aliases = _search_keyboard_h(keyboard) @@ -112,6 +132,7 @@ def info_json(keyboard): for layout_name, layout_json in layouts.items(): if not layout_name.startswith('LAYOUT_kc'): layout_json['c_macro'] = True + layout_json['json_layout'] = False info_data['layouts'][layout_name] = layout_json # Merge in the data from info.json, config.h, and rules.mk @@ -561,8 +582,16 @@ def _process_defaults(info_data): for default_type in defaults_map.keys(): thing_map = defaults_map[default_type] if default_type in info_data: - for key, value in thing_map.get(info_data[default_type], {}).items(): - info_data[key] = value + merged_count = 0 + thing_items = thing_map.get(info_data[default_type], {}).items() + for key, value in thing_items: + if key not in info_data: + info_data[key] = value + merged_count += 1 + + if merged_count == 0 and len(thing_items) > 0: + _log_warning(info_data, 'All defaults for \'%s\' were skipped, potential redundant config or misconfiguration detected' % (default_type)) + return info_data @@ -748,6 +777,7 @@ def arm_processor_rules(info_data, rules): """ info_data['processor_type'] = 'arm' info_data['protocol'] = 'ChibiOS' + info_data['platform_key'] = 'chibios' if 'STM32' in info_data['processor']: info_data['platform'] = 'STM32' @@ -755,6 +785,7 @@ def arm_processor_rules(info_data, rules): info_data['platform'] = rules['MCU_SERIES'] elif 'ARM_ATSAM' in rules: info_data['platform'] = 'ARM_ATSAM' + info_data['platform_key'] = 'arm_atsam' return info_data @@ -764,6 +795,7 @@ def avr_processor_rules(info_data, rules): """ info_data['processor_type'] = 'avr' info_data['platform'] = rules['ARCH'] if 'ARCH' in rules else 'unknown' + info_data['platform_key'] = 'avr' info_data['protocol'] = 'V-USB' if info_data['processor'] in VUSB_PROCESSORS else 'LUFA' # FIXME(fauxpark/anyone): Eventually we should detect the protocol by looking at PROTOCOL inherited from mcu_selection.mk: @@ -818,6 +850,7 @@ def merge_info_jsons(keyboard, info_data): msg = 'Number of keys for %s does not match! info.json specifies %d keys, C macro specifies %d' _log_error(info_data, msg % (layout_name, len(layout['layout']), len(info_data['layouts'][layout_name]['layout']))) else: + info_data['layouts'][layout_name]['json_layout'] = True for new_key, existing_key in zip(layout['layout'], info_data['layouts'][layout_name]['layout']): existing_key.update(new_key) else: @@ -825,6 +858,7 @@ def merge_info_jsons(keyboard, info_data): _log_error(info_data, f'Layout "{layout_name}" has no "matrix" definition in either "info.json" or ".h"!') else: layout['c_macro'] = False + layout['json_layout'] = True info_data['layouts'][layout_name] = layout # Update info_data with the new data @@ -864,6 +898,9 @@ def find_info_json(keyboard): def keymap_json_config(keyboard, keymap): """Extract keymap level config """ + # TODO: resolve keymap.py and info.py circular dependencies + from qmk.keymap import locate_keymap + keymap_folder = locate_keymap(keyboard, keymap).parent km_info_json = parse_configurator_json(keymap_folder / 'keymap.json') @@ -873,6 +910,9 @@ def keymap_json_config(keyboard, keymap): def keymap_json(keyboard, keymap): """Generate the info.json data for a specific keymap. """ + # TODO: resolve keymap.py and info.py circular dependencies + from qmk.keymap import locate_keymap + keymap_folder = locate_keymap(keyboard, keymap).parent # Files to scan -- cgit v1.2.3