summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Challis <git@zvecr.com>2022-11-30 04:27:48 +0000
committerGitHub <noreply@github.com>2022-11-30 04:27:48 +0000
commit17fec52b0fc337ee96dec020e7371ddd5e39cdea (patch)
tree5d5052d6cdf9790275a3af96f9c17768c061139b
parent4a0aa9ada2837762e3b4eab73950962365341cce (diff)
Extend layout lint checks (#19200)
* Extend layout lint checks * Apply suggestions from code review Co-authored-by: Ryan <fauxpark@gmail.com> * Fix function comment Co-authored-by: Ryan <fauxpark@gmail.com>
-rw-r--r--lib/python/qmk/info.py99
1 files changed, 46 insertions, 53 deletions
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py
index 1692d43c9c..0260b624af 100644
--- a/lib/python/qmk/info.py
+++ b/lib/python/qmk/info.py
@@ -1,6 +1,5 @@
"""Functions that help us generate and use info.json files.
"""
-from glob import glob
from pathlib import Path
import jsonschema
@@ -26,6 +25,50 @@ def _valid_community_layout(layout):
return (Path('layouts/default') / layout).exists()
+def _validate(keyboard, info_data):
+ """Perform various validation on the provided info.json data
+ """
+ # First validate against the jsonschema
+ try:
+ validate(info_data, 'qmk.api.keyboard.v1')
+
+ except jsonschema.ValidationError as e:
+ json_path = '.'.join([str(p) for p in e.absolute_path])
+ cli.log.error('Invalid API data: %s: %s: %s', keyboard, json_path, e.message)
+ exit(1)
+
+ layouts = info_data.get('layouts', {})
+ layout_aliases = info_data.get('layout_aliases', {})
+ community_layouts = info_data.get('community_layouts', [])
+
+ # Make sure we have at least one layout
+ if len(layouts) == 0:
+ _log_error(info_data, 'No LAYOUTs defined! Need at least one layout defined in info.json.')
+
+ # 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
+ name_fragments = keyboard.split('/')
+ for layout in layouts.keys():
+ if any(fragment in layout for fragment in name_fragments):
+ _log_warning(info_data, f'Layout "{layout}" should not contain name of keyboard.')
+
+ # Filter out any non-existing community layouts
+ for layout in community_layouts:
+ if not _valid_community_layout(layout):
+ # Ignore layout from future checks
+ info_data['community_layouts'].remove(layout)
+ _log_error(info_data, 'Claims to support a community layout that does not exist: %s' % (layout))
+
+ # Make sure we supply layout macros for the community layouts we claim to support
+ for layout in community_layouts:
+ layout_name = 'LAYOUT_' + layout
+ if layout_name not in layouts and layout_name not in layout_aliases:
+ _log_error(info_data, 'Claims to support community layout %s but no %s() macro found' % (layout, layout_name))
+
+
def info_json(keyboard):
"""Generate the info.json data for a specific keyboard.
"""
@@ -72,34 +115,8 @@ def info_json(keyboard):
# Merge in data from <keyboard.c>
info_data = _extract_led_config(info_data, str(keyboard))
- # Validate against the jsonschema
- try:
- validate(info_data, 'qmk.api.keyboard.v1')
-
- except jsonschema.ValidationError as e:
- json_path = '.'.join([str(p) for p in e.absolute_path])
- cli.log.error('Invalid API data: %s: %s: %s', keyboard, json_path, e.message)
- exit(1)
-
- # Make sure we have at least one layout
- if not info_data.get('layouts'):
- _find_missing_layouts(info_data, keyboard)
-
- if not info_data.get('layouts'):
- _log_error(info_data, 'No LAYOUTs defined! Need at least one layout defined in the keyboard.h or info.json.')
-
- # Filter out any non-existing community layouts
- for layout in info_data.get('community_layouts', []):
- if not _valid_community_layout(layout):
- # Ignore layout from future checks
- info_data['community_layouts'].remove(layout)
- _log_error(info_data, 'Claims to support a community layout that does not exist: %s' % (layout))
-
- # Make sure we supply layout macros for the community layouts we claim to support
- for layout in info_data.get('community_layouts', []):
- layout_name = 'LAYOUT_' + layout
- if layout_name not in info_data.get('layouts', {}) and layout_name not in info_data.get('layout_aliases', {}):
- _log_error(info_data, 'Claims to support community layout %s but no %s() macro found' % (layout, layout_name))
+ # Validate
+ _validate(keyboard, info_data)
# Check that the reported matrix size is consistent with the actual matrix size
_check_matrix(info_data)
@@ -701,30 +718,6 @@ def _search_keyboard_h(keyboard):
return layouts, aliases
-def _find_missing_layouts(info_data, keyboard):
- """Looks for layout macros when they aren't found other places.
-
- If we don't find any layouts from info.json or keyboard.h we widen our search. This is error prone which is why we want to encourage people to follow the standard above.
- """
- _log_warning(info_data, '%s: Falling back to searching for KEYMAP/LAYOUT macros.' % (keyboard))
-
- for file in glob('keyboards/%s/*.h' % keyboard):
- these_layouts, these_aliases = find_layouts(file)
-
- if these_layouts:
- for layout_name, layout_json in these_layouts.items():
- if not layout_name.startswith('LAYOUT_kc'):
- layout_json['c_macro'] = True
- info_data['layouts'][layout_name] = layout_json
-
- for alias, alias_text in these_aliases.items():
- if alias_text in these_layouts:
- if 'layout_aliases' not in info_data:
- info_data['layout_aliases'] = {}
-
- info_data['layout_aliases'][alias] = alias_text
-
-
def _log_error(info_data, message):
"""Send an error message to both JSON and the log.
"""