diff options
| author | Zach White <skullydazed@gmail.com> | 2021-08-28 19:37:55 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-08-29 12:37:55 +1000 |
| commit | 566d59851634bf0ffb5b95dd85f65858b0905dc7 (patch) | |
| tree | 7f632e9c4b08e231bad97e638d2635f9560b10b4 /lib | |
| parent | f155865804da332ac544e6a6bca0ca9035d3e818 (diff) | |
| download | qmk_firmware-566d59851634bf0ffb5b95dd85f65858b0905dc7.tar.gz qmk_firmware-566d59851634bf0ffb5b95dd85f65858b0905dc7.zip | |
Add check for non-assignment code in rules.mk (#12108)
* Add check for non-assignment code in rules.mk
* fix lint check
* fix lint
* fixup to reflect the final state of #8422
* fix lint
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/python/qmk/cli/lint.py | 139 |
1 files changed, 98 insertions, 41 deletions
diff --git a/lib/python/qmk/cli/lint.py b/lib/python/qmk/cli/lint.py index 02b31fbc4..008ec1393 100644 --- a/lib/python/qmk/cli/lint.py +++ b/lib/python/qmk/cli/lint.py | |||
| @@ -1,72 +1,129 @@ | |||
| 1 | """Command to look over a keyboard/keymap and check for common mistakes. | 1 | """Command to look over a keyboard/keymap and check for common mistakes. |
| 2 | """ | 2 | """ |
| 3 | from pathlib import Path | ||
| 4 | |||
| 3 | from milc import cli | 5 | from milc import cli |
| 4 | 6 | ||
| 5 | from qmk.decorators import automagic_keyboard, automagic_keymap | 7 | from qmk.decorators import automagic_keyboard, automagic_keymap |
| 6 | from qmk.info import info_json | 8 | from qmk.info import info_json |
| 7 | from qmk.keyboard import find_readme, keyboard_completer | 9 | from qmk.keyboard import keyboard_completer, list_keyboards |
| 8 | from qmk.keymap import locate_keymap | 10 | from qmk.keymap import locate_keymap |
| 9 | from qmk.path import is_keyboard, keyboard | 11 | from qmk.path import is_keyboard, keyboard |
| 10 | 12 | ||
| 11 | 13 | ||
| 14 | def keymap_check(kb, km): | ||
| 15 | """Perform the keymap level checks. | ||
| 16 | """ | ||
| 17 | ok = True | ||
| 18 | keymap_path = locate_keymap(kb, km) | ||
| 19 | |||
| 20 | if not keymap_path: | ||
| 21 | ok = False | ||
| 22 | cli.log.error("%s: Can't find %s keymap.", kb, km) | ||
| 23 | |||
| 24 | return ok | ||
| 25 | |||
| 26 | |||
| 27 | def rules_mk_assignment_only(keyboard_path): | ||
| 28 | """Check the keyboard-level rules.mk to ensure it only has assignments. | ||
| 29 | """ | ||
| 30 | current_path = Path() | ||
| 31 | errors = [] | ||
| 32 | |||
| 33 | for path_part in keyboard_path.parts: | ||
| 34 | current_path = current_path / path_part | ||
| 35 | rules_mk = current_path / 'rules.mk' | ||
| 36 | |||
| 37 | if rules_mk.exists(): | ||
| 38 | continuation = None | ||
| 39 | |||
| 40 | for i, line in enumerate(rules_mk.open()): | ||
| 41 | line = line.strip() | ||
| 42 | |||
| 43 | if '#' in line: | ||
| 44 | line = line[:line.index('#')] | ||
| 45 | |||
| 46 | if continuation: | ||
| 47 | line = continuation + line | ||
| 48 | continuation = None | ||
| 49 | |||
| 50 | if line: | ||
| 51 | if line[-1] == '\\': | ||
| 52 | continuation = line[:-1] | ||
| 53 | continue | ||
| 54 | |||
| 55 | if line and '=' not in line: | ||
| 56 | errors.append(f'Non-assignment code on line +{i} {rules_mk}: {line}') | ||
| 57 | |||
| 58 | return errors | ||
| 59 | |||
| 60 | |||
| 12 | @cli.argument('--strict', action='store_true', help='Treat warnings as errors.') | 61 | @cli.argument('--strict', action='store_true', help='Treat warnings as errors.') |
| 13 | @cli.argument('-kb', '--keyboard', completer=keyboard_completer, help='The keyboard to check.') | 62 | @cli.argument('-kb', '--keyboard', completer=keyboard_completer, help='The keyboard to check.') |
| 14 | @cli.argument('-km', '--keymap', help='The keymap to check.') | 63 | @cli.argument('-km', '--keymap', help='The keymap to check.') |
| 64 | @cli.argument('--all-kb', action='store_true', arg_only=True, help='Check all keyboards.') | ||
| 15 | @cli.subcommand('Check keyboard and keymap for common mistakes.') | 65 | @cli.subcommand('Check keyboard and keymap for common mistakes.') |
| 16 | @automagic_keyboard | 66 | @automagic_keyboard |
| 17 | @automagic_keymap | 67 | @automagic_keymap |
| 18 | def lint(cli): | 68 | def lint(cli): |
| 19 | """Check keyboard and keymap for common mistakes. | 69 | """Check keyboard and keymap for common mistakes. |
| 20 | """ | 70 | """ |
| 21 | if not cli.config.lint.keyboard: | 71 | failed = [] |
| 22 | cli.log.error('Missing required argument: --keyboard') | ||
| 23 | cli.print_help() | ||
| 24 | return False | ||
| 25 | 72 | ||
| 26 | if not is_keyboard(cli.config.lint.keyboard): | 73 | # Determine our keyboard list |
| 27 | cli.log.error('No such keyboard: %s', cli.config.lint.keyboard) | 74 | if cli.args.all_kb: |
| 28 | return False | 75 | if cli.args.keyboard: |
| 76 | cli.log.warning('Both --all-kb and --keyboard passed, --all-kb takes presidence.') | ||
| 29 | 77 | ||
| 30 | # Gather data about the keyboard. | 78 | keyboard_list = list_keyboards() |
| 31 | ok = True | 79 | elif not cli.config.lint.keyboard: |
| 32 | keyboard_path = keyboard(cli.config.lint.keyboard) | 80 | cli.log.error('Missing required arguments: --keyboard or --all-kb') |
| 33 | keyboard_info = info_json(cli.config.lint.keyboard) | 81 | cli.print_help() |
| 34 | readme_path = find_readme(cli.config.lint.keyboard) | 82 | return False |
| 35 | missing_readme_path = keyboard_path / 'readme.md' | 83 | else: |
| 84 | keyboard_list = cli.args.keyboard.split(',') | ||
| 36 | 85 | ||
| 37 | # Check for errors in the info.json | 86 | # Lint each keyboard |
| 38 | if keyboard_info['parse_errors']: | 87 | for kb in keyboard_list: |
| 39 | ok = False | 88 | if not is_keyboard(kb): |
| 40 | cli.log.error('Errors found when generating info.json.') | 89 | cli.log.error('No such keyboard: %s', kb) |
| 90 | continue | ||
| 41 | 91 | ||
| 42 | if cli.config.lint.strict and keyboard_info['parse_warnings']: | 92 | # Gather data about the keyboard. |
| 43 | ok = False | 93 | ok = True |
| 44 | cli.log.error('Warnings found when generating info.json (Strict mode enabled.)') | 94 | keyboard_path = keyboard(kb) |
| 95 | keyboard_info = info_json(kb) | ||
| 45 | 96 | ||
| 46 | # Check for a readme.md and warn if it doesn't exist | 97 | # Check for errors in the info.json |
| 47 | if not readme_path: | 98 | if keyboard_info['parse_errors']: |
| 48 | ok = False | 99 | ok = False |
| 49 | cli.log.error('Missing %s', missing_readme_path) | 100 | cli.log.error('%s: Errors found when generating info.json.', kb) |
| 50 | 101 | ||
| 51 | # Keymap specific checks | 102 | if cli.config.lint.strict and keyboard_info['parse_warnings']: |
| 52 | if cli.config.lint.keymap: | 103 | ok = False |
| 53 | keymap_path = locate_keymap(cli.config.lint.keyboard, cli.config.lint.keymap) | 104 | cli.log.error('%s: Warnings found when generating info.json (Strict mode enabled.)', kb) |
| 54 | 105 | ||
| 55 | if not keymap_path: | 106 | # Check the rules.mk file(s) |
| 107 | rules_mk_assignment_errors = rules_mk_assignment_only(keyboard_path) | ||
| 108 | if rules_mk_assignment_errors: | ||
| 56 | ok = False | 109 | ok = False |
| 57 | cli.log.error("Can't find %s keymap for %s keyboard.", cli.config.lint.keymap, cli.config.lint.keyboard) | 110 | cli.log.error('%s: Non-assignment code found in rules.mk. Move it to post_rules.mk instead.', kb) |
| 58 | else: | 111 | for assignment_error in rules_mk_assignment_errors: |
| 59 | keymap_readme = keymap_path.parent / 'readme.md' | 112 | cli.log.error(assignment_error) |
| 60 | if not keymap_readme.exists(): | ||
| 61 | cli.log.warning('Missing %s', keymap_readme) | ||
| 62 | 113 | ||
| 63 | if cli.config.lint.strict: | 114 | # Keymap specific checks |
| 64 | ok = False | 115 | if cli.config.lint.keymap: |
| 116 | if not keymap_check(kb, cli.config.lint.keymap): | ||
| 117 | ok = False | ||
| 118 | |||
| 119 | # Report status | ||
| 120 | if not ok: | ||
| 121 | failed.append(kb) | ||
| 65 | 122 | ||
| 66 | # Check and report the overall status | 123 | # Check and report the overall status |
| 67 | if ok: | 124 | if failed: |
| 68 | cli.log.info('Lint check passed!') | 125 | cli.log.error('Lint check failed for: %s', ', '.join(failed)) |
| 69 | return True | 126 | return False |
| 70 | 127 | ||
| 71 | cli.log.error('Lint check failed!') | 128 | cli.log.info('Lint check passed!') |
| 72 | return False | 129 | return True |
