diff options
| author | Joel Challis <git@zvecr.com> | 2025-04-23 01:27:47 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-23 10:27:47 +1000 |
| commit | 8cd71917ce74dd8301e24d80f4eabb2bfa1a7c69 (patch) | |
| tree | 8b12d8679d1ce7633339a387e0b627eb8df2a3e5 /lib/python | |
| parent | 7a2cd0fa962eb5e6e18ce8b0213a7171bc823c1f (diff) | |
Avoid duplication in generated community modules `rules.mk` (#25135)
Diffstat (limited to 'lib/python')
| -rw-r--r-- | lib/python/qmk/cli/generate/community_modules.py | 65 | ||||
| -rwxr-xr-x | lib/python/qmk/cli/generate/rules_mk.py | 36 | ||||
| -rw-r--r-- | lib/python/qmk/info.py | 16 |
3 files changed, 69 insertions, 48 deletions
diff --git a/lib/python/qmk/cli/generate/community_modules.py b/lib/python/qmk/cli/generate/community_modules.py index 23678a2fb5..e12daccf1c 100644 --- a/lib/python/qmk/cli/generate/community_modules.py +++ b/lib/python/qmk/cli/generate/community_modules.py | |||
| @@ -8,7 +8,7 @@ import qmk.path | |||
| 8 | from qmk.info import get_modules | 8 | from qmk.info import get_modules |
| 9 | from qmk.keyboard import keyboard_completer, keyboard_folder | 9 | from qmk.keyboard import keyboard_completer, keyboard_folder |
| 10 | from qmk.commands import dump_lines | 10 | from qmk.commands import dump_lines |
| 11 | from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE | 11 | from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, GPL2_HEADER_SH_LIKE, GENERATED_HEADER_SH_LIKE |
| 12 | from qmk.community_modules import module_api_list, load_module_jsons, find_module_path | 12 | from qmk.community_modules import module_api_list, load_module_jsons, find_module_path |
| 13 | 13 | ||
| 14 | 14 | ||
| @@ -121,6 +121,69 @@ def _render_core_implementation(api, modules): | |||
| 121 | return lines | 121 | return lines |
| 122 | 122 | ||
| 123 | 123 | ||
| 124 | def _generate_features_rules(features_dict): | ||
| 125 | lines = [] | ||
| 126 | for feature, enabled in features_dict.items(): | ||
| 127 | feature = feature.upper() | ||
| 128 | enabled = 'yes' if enabled else 'no' | ||
| 129 | lines.append(f'{feature}_ENABLE={enabled}') | ||
| 130 | return lines | ||
| 131 | |||
| 132 | |||
| 133 | def _generate_modules_rules(keyboard, filename): | ||
| 134 | lines = [] | ||
| 135 | modules = get_modules(keyboard, filename) | ||
| 136 | if len(modules) > 0: | ||
| 137 | lines.append('') | ||
| 138 | lines.append('OPT_DEFS += -DCOMMUNITY_MODULES_ENABLE=TRUE') | ||
| 139 | for module in modules: | ||
| 140 | module_path = qmk.path.unix_style_path(find_module_path(module)) | ||
| 141 | if not module_path: | ||
| 142 | raise FileNotFoundError(f"Module '{module}' not found.") | ||
| 143 | lines.append('') | ||
| 144 | lines.append(f'COMMUNITY_MODULES += {module_path.name}') # use module_path here instead of module as it may be a subdirectory | ||
| 145 | lines.append(f'OPT_DEFS += -DCOMMUNITY_MODULE_{module_path.name.upper()}_ENABLE=TRUE') | ||
| 146 | lines.append(f'COMMUNITY_MODULE_PATHS += {module_path}') | ||
| 147 | lines.append(f'VPATH += {module_path}') | ||
| 148 | lines.append(f'SRC += $(wildcard {module_path}/{module_path.name}.c)') | ||
| 149 | lines.append(f'MODULE_NAME_{module_path.name.upper()} := {module_path.name}') | ||
| 150 | lines.append(f'MODULE_PATH_{module_path.name.upper()} := {module_path}') | ||
| 151 | lines.append(f'-include {module_path}/rules.mk') | ||
| 152 | |||
| 153 | module_jsons = load_module_jsons(modules) | ||
| 154 | for module_json in module_jsons: | ||
| 155 | if 'features' in module_json: | ||
| 156 | lines.append('') | ||
| 157 | lines.append(f'# Module: {module_json["module_name"]}') | ||
| 158 | lines.extend(_generate_features_rules(module_json['features'])) | ||
| 159 | return lines | ||
| 160 | |||
| 161 | |||
| 162 | @cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') | ||
| 163 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") | ||
| 164 | @cli.argument('-e', '--escape', arg_only=True, action='store_true', help="Escape spaces in quiet mode") | ||
| 165 | @cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate rules.mk for.') | ||
| 166 | @cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), completer=FilesCompleter('.json'), help='A configurator export JSON to be compiled and flashed or a pre-compiled binary firmware file (bin/hex) to be flashed.') | ||
| 167 | @cli.subcommand('Creates a community_modules_rules_mk from a keymap.json file.') | ||
| 168 | def generate_community_modules_rules_mk(cli): | ||
| 169 | |||
| 170 | rules_mk_lines = [GPL2_HEADER_SH_LIKE, GENERATED_HEADER_SH_LIKE] | ||
| 171 | |||
| 172 | rules_mk_lines.extend(_generate_modules_rules(cli.args.keyboard, cli.args.filename)) | ||
| 173 | |||
| 174 | # Show the results | ||
| 175 | dump_lines(cli.args.output, rules_mk_lines) | ||
| 176 | |||
| 177 | if cli.args.output: | ||
| 178 | if cli.args.quiet: | ||
| 179 | if cli.args.escape: | ||
| 180 | print(cli.args.output.as_posix().replace(' ', '\\ ')) | ||
| 181 | else: | ||
| 182 | print(cli.args.output) | ||
| 183 | else: | ||
| 184 | cli.log.info('Wrote rules.mk to %s.', cli.args.output) | ||
| 185 | |||
| 186 | |||
| 124 | @cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') | 187 | @cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') |
| 125 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") | 188 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") |
| 126 | @cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate community_modules.h for.') | 189 | @cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate community_modules.h for.') |
diff --git a/lib/python/qmk/cli/generate/rules_mk.py b/lib/python/qmk/cli/generate/rules_mk.py index 01d71d277f..358a22fd1d 100755 --- a/lib/python/qmk/cli/generate/rules_mk.py +++ b/lib/python/qmk/cli/generate/rules_mk.py | |||
| @@ -6,13 +6,12 @@ from dotty_dict import dotty | |||
| 6 | from argcomplete.completers import FilesCompleter | 6 | from argcomplete.completers import FilesCompleter |
| 7 | from milc import cli | 7 | from milc import cli |
| 8 | 8 | ||
| 9 | from qmk.info import info_json, get_modules | 9 | from qmk.info import info_json |
| 10 | from qmk.json_schema import json_load | 10 | from qmk.json_schema import json_load |
| 11 | from qmk.keyboard import keyboard_completer, keyboard_folder | 11 | from qmk.keyboard import keyboard_completer, keyboard_folder |
| 12 | from qmk.commands import dump_lines, parse_configurator_json | 12 | from qmk.commands import dump_lines, parse_configurator_json |
| 13 | from qmk.path import normpath, unix_style_path, FileType | 13 | from qmk.path import normpath, FileType |
| 14 | from qmk.constants import GPL2_HEADER_SH_LIKE, GENERATED_HEADER_SH_LIKE | 14 | from qmk.constants import GPL2_HEADER_SH_LIKE, GENERATED_HEADER_SH_LIKE |
| 15 | from qmk.community_modules import find_module_path, load_module_jsons | ||
| 16 | 15 | ||
| 17 | 16 | ||
| 18 | def generate_rule(rules_key, rules_value): | 17 | def generate_rule(rules_key, rules_value): |
| @@ -56,35 +55,6 @@ def generate_features_rules(features_dict): | |||
| 56 | return lines | 55 | return lines |
| 57 | 56 | ||
| 58 | 57 | ||
| 59 | def generate_modules_rules(keyboard, filename): | ||
| 60 | lines = [] | ||
| 61 | modules = get_modules(keyboard, filename) | ||
| 62 | if len(modules) > 0: | ||
| 63 | lines.append('') | ||
| 64 | lines.append('OPT_DEFS += -DCOMMUNITY_MODULES_ENABLE=TRUE') | ||
| 65 | for module in modules: | ||
| 66 | module_path = unix_style_path(find_module_path(module)) | ||
| 67 | if not module_path: | ||
| 68 | raise FileNotFoundError(f"Module '{module}' not found.") | ||
| 69 | lines.append('') | ||
| 70 | lines.append(f'COMMUNITY_MODULES += {module_path.name}') # use module_path here instead of module as it may be a subdirectory | ||
| 71 | lines.append(f'OPT_DEFS += -DCOMMUNITY_MODULE_{module_path.name.upper()}_ENABLE=TRUE') | ||
| 72 | lines.append(f'COMMUNITY_MODULE_PATHS += {module_path}') | ||
| 73 | lines.append(f'VPATH += {module_path}') | ||
| 74 | lines.append(f'SRC += $(wildcard {module_path}/{module_path.name}.c)') | ||
| 75 | lines.append(f'MODULE_NAME_{module_path.name.upper()} := {module_path.name}') | ||
| 76 | lines.append(f'MODULE_PATH_{module_path.name.upper()} := {module_path}') | ||
| 77 | lines.append(f'-include {module_path}/rules.mk') | ||
| 78 | |||
| 79 | module_jsons = load_module_jsons(modules) | ||
| 80 | for module_json in module_jsons: | ||
| 81 | if 'features' in module_json: | ||
| 82 | lines.append('') | ||
| 83 | lines.append(f'# Module: {module_json["module_name"]}') | ||
| 84 | lines.extend(generate_features_rules(module_json['features'])) | ||
| 85 | return lines | ||
| 86 | |||
| 87 | |||
| 88 | @cli.argument('filename', nargs='?', arg_only=True, type=FileType('r'), completer=FilesCompleter('.json'), help='A configurator export JSON to be compiled and flashed or a pre-compiled binary firmware file (bin/hex) to be flashed.') | 58 | @cli.argument('filename', nargs='?', arg_only=True, type=FileType('r'), completer=FilesCompleter('.json'), help='A configurator export JSON to be compiled and flashed or a pre-compiled binary firmware file (bin/hex) to be flashed.') |
| 89 | @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') | 59 | @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') |
| 90 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") | 60 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") |
| @@ -135,8 +105,6 @@ def generate_rules_mk(cli): | |||
| 135 | if converter: | 105 | if converter: |
| 136 | rules_mk_lines.append(generate_rule('CONVERT_TO', converter)) | 106 | rules_mk_lines.append(generate_rule('CONVERT_TO', converter)) |
| 137 | 107 | ||
| 138 | rules_mk_lines.extend(generate_modules_rules(cli.args.keyboard, cli.args.filename)) | ||
| 139 | |||
| 140 | # Show the results | 108 | # Show the results |
| 141 | dump_lines(cli.args.output, rules_mk_lines) | 109 | dump_lines(cli.args.output, rules_mk_lines) |
| 142 | 110 | ||
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py index 93eba7376a..d95fd3d799 100644 --- a/lib/python/qmk/info.py +++ b/lib/python/qmk/info.py | |||
| @@ -1066,23 +1066,13 @@ def get_modules(keyboard, keymap_filename): | |||
| 1066 | """ | 1066 | """ |
| 1067 | modules = [] | 1067 | modules = [] |
| 1068 | 1068 | ||
| 1069 | kb_info_json = info_json(keyboard) | ||
| 1070 | modules.extend(kb_info_json.get('modules', [])) | ||
| 1071 | |||
| 1069 | if keymap_filename: | 1072 | if keymap_filename: |
| 1070 | keymap_json = parse_configurator_json(keymap_filename) | 1073 | keymap_json = parse_configurator_json(keymap_filename) |
| 1071 | 1074 | ||
| 1072 | if keymap_json: | 1075 | if keymap_json: |
| 1073 | kb = keymap_json.get('keyboard', None) | ||
| 1074 | if not kb: | ||
| 1075 | kb = keyboard | ||
| 1076 | |||
| 1077 | if kb: | ||
| 1078 | kb_info_json = info_json(kb) | ||
| 1079 | if kb_info_json: | ||
| 1080 | modules.extend(kb_info_json.get('modules', [])) | ||
| 1081 | |||
| 1082 | modules.extend(keymap_json.get('modules', [])) | 1076 | modules.extend(keymap_json.get('modules', [])) |
| 1083 | 1077 | ||
| 1084 | elif keyboard: | ||
| 1085 | kb_info_json = info_json(keyboard) | ||
| 1086 | modules.extend(kb_info_json.get('modules', [])) | ||
| 1087 | |||
| 1088 | return list(dict.fromkeys(modules)) # remove dupes | 1078 | return list(dict.fromkeys(modules)) # remove dupes |
