From f1f85b53a05fba3b576ca06bc68ccde6a3e4a8e8 Mon Sep 17 00:00:00 2001 From: zvecr Date: Sat, 14 May 2022 19:45:05 +0100 Subject: [PATCH 1/3] Perform stricter lint checks --- lib/python/qmk/cli/lint.py | 123 +++++++++++++++++++++++++------------ lib/python/qmk/git.py | 9 +++ 2 files changed, 94 insertions(+), 38 deletions(-) diff --git a/lib/python/qmk/cli/lint.py b/lib/python/qmk/cli/lint.py index af057b41101a..be12a7ee0d0e 100644 --- a/lib/python/qmk/cli/lint.py +++ b/lib/python/qmk/cli/lint.py @@ -6,27 +6,44 @@ from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.info import info_json -from qmk.keyboard import keyboard_completer, list_keyboards -from qmk.keymap import locate_keymap +from qmk.keyboard import keyboard_completer, keyboard_folder, list_keyboards +from qmk.keymap import locate_keymap, list_keymaps from qmk.path import is_keyboard, keyboard +from qmk.git import git_get_ignored_files -def keymap_check(kb, km): - """Perform the keymap level checks. +def _list_defaultish_keymaps(kb): + """Return default like keymaps for a given keyboard """ - ok = True - keymap_path = locate_keymap(kb, km) + defaultish = ['ansi', 'iso', 'via'] - if not keymap_path: + keymaps = set() + for x in list_keymaps(kb): + if x in defaultish or x.startswith('default'): + keymaps.add(x) + + return keymaps + + +def _handle_json_errors(kb, info): + """Convert any json errors into lint errors + """ + ok = True + # Check for errors in the json + if info['parse_errors']: ok = False - cli.log.error("%s: Can't find %s keymap.", kb, km) + cli.log.error(f'{kb}: Errors found when generating info.json.') + if cli.config.lint.strict and info['parse_warnings']: + ok = False + cli.log.error(f'{kb}: Warnings found when generating info.json (Strict mode enabled.)') return ok -def rules_mk_assignment_only(keyboard_path): +def _rules_mk_assignment_only(kb): """Check the keyboard-level rules.mk to ensure it only has assignments. """ + keyboard_path = keyboard(kb) current_path = Path() errors = [] @@ -58,8 +75,53 @@ def rules_mk_assignment_only(keyboard_path): return errors +def keymap_check(kb, km): + """Perform the keymap level checks. + """ + ok = True + keymap_path = locate_keymap(kb, km) + + if not keymap_path: + ok = False + cli.log.error("%s: Can't find %s keymap.", kb, km) + return ok + + # Additional checks + invalid_files = git_get_ignored_files(keymap_path.parent) + for file in invalid_files: + cli.log.error(f'{kb}/{km}: The file "{file}" should not exist!') + ok = False + + return ok + + +def keyboard_check(kb): + """Perform the keyboard level checks. + """ + ok = True + kb_info = info_json(kb) + + if not _handle_json_errors(kb, kb_info): + ok = False + + # Additional checks + rules_mk_assignment_errors = _rules_mk_assignment_only(kb) + if rules_mk_assignment_errors: + ok = False + cli.log.error('%s: Non-assignment code found in rules.mk. Move it to post_rules.mk instead.', kb) + for assignment_error in rules_mk_assignment_errors: + cli.log.error(assignment_error) + + invalid_files = git_get_ignored_files(f'keyboards/{kb}/') + for file in invalid_files: + cli.log.error(f'{kb}: The file "{file}" should not exist!') + ok = False + + return ok + + @cli.argument('--strict', action='store_true', help='Treat warnings as errors') -@cli.argument('-kb', '--keyboard', completer=keyboard_completer, help='Comma separated list of keyboards to check') +@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Comma separated list of keyboards to check') @cli.argument('-km', '--keymap', help='The keymap to check') @cli.argument('--all-kb', action='store_true', arg_only=True, help='Check all keyboards') @cli.subcommand('Check keyboard and keymap for common mistakes.') @@ -73,7 +135,7 @@ def lint(cli): # Determine our keyboard list if cli.args.all_kb: if cli.args.keyboard: - cli.log.warning('Both --all-kb and --keyboard passed, --all-kb takes presidence.') + cli.log.warning('Both --all-kb and --keyboard passed, --all-kb takes precedence.') keyboard_list = list_keyboards() elif not cli.config.lint.keyboard: @@ -89,38 +151,23 @@ def lint(cli): cli.log.error('No such keyboard: %s', kb) continue - # Gather data about the keyboard. - ok = True - keyboard_path = keyboard(kb) - keyboard_info = info_json(kb) - - # Check for errors in the info.json - if keyboard_info['parse_errors']: - ok = False - cli.log.error('%s: Errors found when generating info.json.', kb) + # Determine keymaps to also check + if cli.config.lint.keymap: + keymaps = {cli.config.lint.keymap} + else: + keymaps = _list_defaultish_keymaps(kb) + # Ensure that at least a 'default' keymap always exists + keymaps.add('default') - if cli.config.lint.strict and keyboard_info['parse_warnings']: - ok = False - cli.log.error('%s: Warnings found when generating info.json (Strict mode enabled.)', kb) + ok = True - # Check the rules.mk file(s) - rules_mk_assignment_errors = rules_mk_assignment_only(keyboard_path) - if rules_mk_assignment_errors: + # keyboard level checks + if not keyboard_check(kb): ok = False - cli.log.error('%s: Non-assignment code found in rules.mk. Move it to post_rules.mk instead.', kb) - for assignment_error in rules_mk_assignment_errors: - cli.log.error(assignment_error) # Keymap specific checks - if cli.config.lint.keymap: - if not keymap_check(kb, cli.config.lint.keymap): - ok = False - - # Check if all non-data driven macros exist in - for layout, data in keyboard_info['layouts'].items(): - # Matrix data should be a list with exactly two integers: [0, 1] - if not data['c_macro'] and not all('matrix' in key_data.keys() or len(key_data) == 2 or all(isinstance(n, int) for n in key_data) for key_data in data['layout']): - cli.log.error(f'{kb}: "{layout}" has no "matrix" definition in either "info.json" or ".h"!') + for keymap in keymaps: + if not keymap_check(kb, keymap): ok = False # Report status diff --git a/lib/python/qmk/git.py b/lib/python/qmk/git.py index beeb68914498..f493628492ab 100644 --- a/lib/python/qmk/git.py +++ b/lib/python/qmk/git.py @@ -108,3 +108,12 @@ def git_check_deviation(active_branch): cli.run(['git', 'fetch', 'upstream', active_branch]) deviations = cli.run(['git', '--no-pager', 'log', f'upstream/{active_branch}...{active_branch}']) return bool(deviations.returncode) + + +def git_get_ignored_files(check_dir='.'): + """Return a list of files that would be captured by the current .gitingore + """ + invalid = cli.run(['git', 'ls-files', '-c', '-o', '-i', '--exclude-standard', check_dir]) + if invalid.returncode != 0: + return [] + return invalid.stdout.strip().splitlines() From 563e6a2f3c69056d49525747011377be064886af Mon Sep 17 00:00:00 2001 From: zvecr Date: Fri, 10 Jun 2022 13:03:09 +0100 Subject: [PATCH 2/3] provide a method to lint all keymaps for a given keyboard --- lib/python/qmk/cli/lint.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/python/qmk/cli/lint.py b/lib/python/qmk/cli/lint.py index be12a7ee0d0e..8ccec8089cb6 100644 --- a/lib/python/qmk/cli/lint.py +++ b/lib/python/qmk/cli/lint.py @@ -114,6 +114,8 @@ def keyboard_check(kb): invalid_files = git_get_ignored_files(f'keyboards/{kb}/') for file in invalid_files: + if 'keymap' in file: + continue cli.log.error(f'{kb}: The file "{file}" should not exist!') ok = False @@ -124,6 +126,7 @@ def keyboard_check(kb): @cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Comma separated list of keyboards to check') @cli.argument('-km', '--keymap', help='The keymap to check') @cli.argument('--all-kb', action='store_true', arg_only=True, help='Check all keyboards') +@cli.argument('--all-km', action='store_true', arg_only=True, help='Check all keymaps') @cli.subcommand('Check keyboard and keymap for common mistakes.') @automagic_keyboard @automagic_keymap @@ -152,7 +155,9 @@ def lint(cli): continue # Determine keymaps to also check - if cli.config.lint.keymap: + if cli.args.all_km: + keymaps = list_keymaps(kb) + elif cli.config.lint.keymap: keymaps = {cli.config.lint.keymap} else: keymaps = _list_defaultish_keymaps(kb) From a438ca74fe71469a0990b0cdbada9f9e999d1061 Mon Sep 17 00:00:00 2001 From: zvecr Date: Fri, 10 Jun 2022 13:13:28 +0100 Subject: [PATCH 3/3] remove alias handling as it breaks csv --- lib/python/qmk/cli/lint.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/python/qmk/cli/lint.py b/lib/python/qmk/cli/lint.py index 8ccec8089cb6..38b6457c43fa 100644 --- a/lib/python/qmk/cli/lint.py +++ b/lib/python/qmk/cli/lint.py @@ -6,7 +6,7 @@ from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.info import info_json -from qmk.keyboard import keyboard_completer, keyboard_folder, list_keyboards +from qmk.keyboard import keyboard_completer, list_keyboards from qmk.keymap import locate_keymap, list_keymaps from qmk.path import is_keyboard, keyboard from qmk.git import git_get_ignored_files @@ -123,7 +123,7 @@ def keyboard_check(kb): @cli.argument('--strict', action='store_true', help='Treat warnings as errors') -@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Comma separated list of keyboards to check') +@cli.argument('-kb', '--keyboard', completer=keyboard_completer, help='Comma separated list of keyboards to check') @cli.argument('-km', '--keymap', help='The keymap to check') @cli.argument('--all-kb', action='store_true', arg_only=True, help='Check all keyboards') @cli.argument('--all-km', action='store_true', arg_only=True, help='Check all keymaps')