mirror of
https://github.com/zsa/qmk_firmware.git
synced 2026-03-13 21:45:22 +00:00
Merge remote-tracking branch 'upstream/master' into firmware23
This commit is contained in:
@@ -39,6 +39,7 @@ subcommands = [
|
||||
'qmk.cli.compile',
|
||||
'qmk.cli.docs',
|
||||
'qmk.cli.doctor',
|
||||
'qmk.cli.find',
|
||||
'qmk.cli.flash',
|
||||
'qmk.cli.format.c',
|
||||
'qmk.cli.format.json',
|
||||
@@ -56,6 +57,7 @@ subcommands = [
|
||||
'qmk.cli.generate.keyboard_h',
|
||||
'qmk.cli.generate.keycodes',
|
||||
'qmk.cli.generate.keycodes_tests',
|
||||
'qmk.cli.generate.make_dependencies',
|
||||
'qmk.cli.generate.rgb_breathe_table',
|
||||
'qmk.cli.generate.rules_mk',
|
||||
'qmk.cli.generate.version_h',
|
||||
|
||||
@@ -57,7 +57,7 @@ def c2json(cli):
|
||||
cli.args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
if cli.args.output.exists():
|
||||
cli.args.output.replace(cli.args.output.parent / (cli.args.output.name + '.bak'))
|
||||
cli.args.output.write_text(json.dumps(keymap_json, cls=InfoJSONEncoder))
|
||||
cli.args.output.write_text(json.dumps(keymap_json, cls=InfoJSONEncoder, sort_keys=True))
|
||||
|
||||
if not cli.args.quiet:
|
||||
cli.log.info('Wrote keymap to %s.', cli.args.output)
|
||||
|
||||
31
lib/python/qmk/cli/find.py
Normal file
31
lib/python/qmk/cli/find.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""Command to search through all keyboards and keymaps for a given search criteria.
|
||||
"""
|
||||
from milc import cli
|
||||
from qmk.search import search_keymap_targets
|
||||
|
||||
|
||||
@cli.argument(
|
||||
'-f',
|
||||
'--filter',
|
||||
arg_only=True,
|
||||
action='append',
|
||||
default=[],
|
||||
help= # noqa: `format-python` and `pytest` don't agree here.
|
||||
"Filter the list of keyboards based on their info.json data. Accepts the formats key=value, function(key), or function(key,value), eg. 'features.rgblight=true'. Valid functions are 'absent', 'contains', 'exists' and 'length'. May be passed multiple times; all filters need to match. Value may include wildcards such as '*' and '?'." # noqa: `format-python` and `pytest` don't agree here.
|
||||
)
|
||||
@cli.argument('-p', '--print', arg_only=True, action='append', default=[], help="For each matched target, print the value of the supplied info.json key. May be passed multiple times.")
|
||||
@cli.argument('-km', '--keymap', type=str, default='default', help="The keymap name to build. Default is 'default'.")
|
||||
@cli.subcommand('Find builds which match supplied search criteria.')
|
||||
def find(cli):
|
||||
"""Search through all keyboards and keymaps for a given search criteria.
|
||||
"""
|
||||
|
||||
if len(cli.args.filter) == 0 and len(cli.args.print) > 0:
|
||||
cli.log.warning('No filters supplied -- keymaps not parsed, unable to print requested values.')
|
||||
|
||||
targets = search_keymap_targets(cli.args.keymap, cli.args.filter, cli.args.print)
|
||||
for keyboard, keymap, print_vals in targets:
|
||||
print(f'{keyboard}:{keymap}')
|
||||
|
||||
for key, val in print_vals:
|
||||
print(f' {key}={val}')
|
||||
@@ -62,4 +62,4 @@ def format_json(cli):
|
||||
json_file['layers'][layer_num] = current_layer
|
||||
|
||||
# Display the results
|
||||
print(json.dumps(json_file, cls=json_encoder))
|
||||
print(json.dumps(json_file, cls=json_encoder, sort_keys=True))
|
||||
|
||||
@@ -7,7 +7,7 @@ from milc import cli
|
||||
from qmk.path import normpath
|
||||
|
||||
py_file_suffixes = ('py',)
|
||||
py_dirs = ['lib/python']
|
||||
py_dirs = ['lib/python', 'util/ci']
|
||||
|
||||
|
||||
def yapf_run(files):
|
||||
|
||||
@@ -8,7 +8,6 @@ from milc import cli
|
||||
|
||||
from qmk.datetime import current_datetime
|
||||
from qmk.info import info_json
|
||||
from qmk.json_encoders import InfoJSONEncoder
|
||||
from qmk.json_schema import json_load
|
||||
from qmk.keymap import list_keymaps
|
||||
from qmk.keyboard import find_readme, list_keyboards
|
||||
@@ -43,14 +42,14 @@ def _resolve_keycode_specs(output_folder):
|
||||
overall = load_spec(version)
|
||||
|
||||
output_file = output_folder / f'constants/keycodes_{version}.json'
|
||||
output_file.write_text(json.dumps(overall), encoding='utf-8')
|
||||
output_file.write_text(json.dumps(overall, separators=(',', ':')), encoding='utf-8')
|
||||
|
||||
for lang in list_languages():
|
||||
for version in list_versions(lang):
|
||||
overall = load_spec(version, lang)
|
||||
|
||||
output_file = output_folder / f'constants/keycodes_{lang}_{version}.json'
|
||||
output_file.write_text(json.dumps(overall, indent=4), encoding='utf-8')
|
||||
output_file.write_text(json.dumps(overall, separators=(',', ':')), encoding='utf-8')
|
||||
|
||||
# Purge files consumed by 'load_spec'
|
||||
shutil.rmtree(output_folder / 'constants/keycodes/')
|
||||
@@ -64,6 +63,12 @@ def _filtered_copy(src, dst):
|
||||
data = json_load(src)
|
||||
|
||||
dst = dst.with_suffix('.json')
|
||||
dst.write_text(json.dumps(data, separators=(',', ':')), encoding='utf-8')
|
||||
return dst
|
||||
|
||||
if dst.suffix == '.jsonschema':
|
||||
data = json_load(src)
|
||||
|
||||
dst.write_text(json.dumps(data), encoding='utf-8')
|
||||
return dst
|
||||
|
||||
@@ -130,7 +135,7 @@ def generate_api(cli):
|
||||
}
|
||||
|
||||
keyboard_dir.mkdir(parents=True, exist_ok=True)
|
||||
keyboard_json = json.dumps({'last_updated': current_datetime(), 'keyboards': {keyboard_name: kb_json}})
|
||||
keyboard_json = json.dumps({'last_updated': current_datetime(), 'keyboards': {keyboard_name: kb_json}}, separators=(',', ':'))
|
||||
if not cli.args.dry_run:
|
||||
keyboard_info.write_text(keyboard_json, encoding='utf-8')
|
||||
cli.log.debug('Wrote file %s', keyboard_info)
|
||||
@@ -144,7 +149,7 @@ def generate_api(cli):
|
||||
keymap_hjson = kb_json['keymaps'][keymap]['path']
|
||||
keymap_json = v1_dir / keymap_hjson
|
||||
keymap_json.parent.mkdir(parents=True, exist_ok=True)
|
||||
keymap_json.write_text(json.dumps(json_load(Path(keymap_hjson))), encoding='utf-8')
|
||||
keymap_json.write_text(json.dumps(json_load(Path(keymap_hjson)), separators=(',', ':')), encoding='utf-8')
|
||||
cli.log.debug('Wrote keymap %s', keymap_json)
|
||||
|
||||
if 'usb' in kb_json:
|
||||
@@ -173,12 +178,12 @@ def generate_api(cli):
|
||||
_resolve_keycode_specs(v1_dir)
|
||||
|
||||
# Write the global JSON files
|
||||
keyboard_all_json = json.dumps({'last_updated': current_datetime(), 'keyboards': kb_all}, cls=InfoJSONEncoder)
|
||||
usb_json = json.dumps({'last_updated': current_datetime(), 'usb': usb_list}, cls=InfoJSONEncoder)
|
||||
keyboard_list_json = json.dumps({'last_updated': current_datetime(), 'keyboards': keyboard_list}, cls=InfoJSONEncoder)
|
||||
keyboard_aliases_json = json.dumps({'last_updated': current_datetime(), 'keyboard_aliases': keyboard_aliases}, cls=InfoJSONEncoder)
|
||||
keyboard_metadata_json = json.dumps(keyboard_metadata, cls=InfoJSONEncoder)
|
||||
constants_metadata_json = json.dumps({'last_updated': current_datetime(), 'constants': _list_constants(v1_dir)})
|
||||
keyboard_all_json = json.dumps({'last_updated': current_datetime(), 'keyboards': kb_all}, separators=(',', ':'))
|
||||
usb_json = json.dumps({'last_updated': current_datetime(), 'usb': usb_list}, separators=(',', ':'))
|
||||
keyboard_list_json = json.dumps({'last_updated': current_datetime(), 'keyboards': keyboard_list}, separators=(',', ':'))
|
||||
keyboard_aliases_json = json.dumps({'last_updated': current_datetime(), 'keyboard_aliases': keyboard_aliases}, separators=(',', ':'))
|
||||
keyboard_metadata_json = json.dumps(keyboard_metadata, separators=(',', ':'))
|
||||
constants_metadata_json = json.dumps({'last_updated': current_datetime(), 'constants': _list_constants(v1_dir)}, separators=(',', ':'))
|
||||
|
||||
if not cli.args.dry_run:
|
||||
keyboard_all_file.write_text(keyboard_all_json, encoding='utf-8')
|
||||
|
||||
@@ -63,7 +63,13 @@ def parse_file(file_name: str) -> List[Tuple[str, str]]:
|
||||
"""
|
||||
|
||||
try:
|
||||
import english_words
|
||||
correct_words = english_words.get_english_words_set(['web2'], lower=True, alpha=True)
|
||||
except AttributeError:
|
||||
from english_words import english_words_lower_alpha_set as correct_words
|
||||
if not cli.args.quiet:
|
||||
cli.echo('The english_words package is outdated, update by running:')
|
||||
cli.echo(' {fg_cyan}python3 -m pip install english_words --upgrade')
|
||||
except ImportError:
|
||||
if not cli.args.quiet:
|
||||
cli.echo('Autocorrection will falsely trigger when a typo is a substring of a correctly spelled word.')
|
||||
|
||||
@@ -15,6 +15,8 @@ from milc import cli, MILC
|
||||
from qmk.commands import create_make_command
|
||||
from qmk.constants import QMK_FIRMWARE
|
||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||
from qmk.keymap import keymap_completer
|
||||
|
||||
|
||||
@lru_cache(maxsize=10)
|
||||
@@ -74,8 +76,8 @@ def parse_make_n(f: Iterator[str]) -> List[Dict[str, str]]:
|
||||
return records
|
||||
|
||||
|
||||
@cli.argument('-kb', '--keyboard', help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.')
|
||||
@cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Ignored when a configurator export is supplied.')
|
||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard\'s name')
|
||||
@cli.argument('-km', '--keymap', completer=keymap_completer, help='The keymap\'s name')
|
||||
@cli.subcommand('Create a compilation database.')
|
||||
@automagic_keyboard
|
||||
@automagic_keymap
|
||||
@@ -104,7 +106,7 @@ def generate_compilation_database(cli: MILC) -> Union[bool, int]:
|
||||
|
||||
if not command:
|
||||
cli.log.error('You must supply both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.')
|
||||
cli.echo('usage: qmk compiledb [-kb KEYBOARD] [-km KEYMAP]')
|
||||
cli.echo('usage: qmk generate-compilation-database [-kb KEYBOARD] [-km KEYMAP]')
|
||||
return False
|
||||
|
||||
# remove any environment variable overrides which could trip us up
|
||||
|
||||
@@ -119,7 +119,9 @@ def generate_encoder_config(encoder_json, config_h_lines, postfix=''):
|
||||
config_h_lines.append(generate_define(f'ENCODERS_PAD_B{postfix}', f'{{ {", ".join(b_pads)} }}'))
|
||||
|
||||
if None in resolutions:
|
||||
cli.log.debug("Unable to generate ENCODER_RESOLUTION configuration")
|
||||
cli.log.debug(f"Unable to generate ENCODER_RESOLUTION{postfix} configuration")
|
||||
elif len(resolutions) == 0:
|
||||
cli.log.debug(f"Skipping ENCODER_RESOLUTION{postfix} configuration")
|
||||
elif len(set(resolutions)) == 1:
|
||||
config_h_lines.append(generate_define(f'ENCODER_RESOLUTION{postfix}', resolutions[0]))
|
||||
else:
|
||||
|
||||
@@ -76,7 +76,7 @@ def generate_info_json(cli):
|
||||
# Build the info.json file
|
||||
kb_info_json = info_json(cli.config.generate_info_json.keyboard)
|
||||
strip_info_json(kb_info_json)
|
||||
info_json_text = json.dumps(kb_info_json, indent=4, cls=InfoJSONEncoder)
|
||||
info_json_text = json.dumps(kb_info_json, indent=4, cls=InfoJSONEncoder, sort_keys=True)
|
||||
|
||||
if cli.args.output:
|
||||
# Write to a file
|
||||
|
||||
@@ -11,12 +11,9 @@ from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||
from qmk.constants import COL_LETTERS, ROW_LETTERS, GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
|
||||
|
||||
|
||||
def _generate_layouts(keyboard):
|
||||
"""Generates the layouts.h file.
|
||||
def _generate_layouts(keyboard, kb_info_json):
|
||||
"""Generates the layouts macros.
|
||||
"""
|
||||
# Build the info.json file
|
||||
kb_info_json = info_json(keyboard)
|
||||
|
||||
if 'matrix_size' not in kb_info_json:
|
||||
cli.log.error(f'{keyboard}: Invalid matrix config.')
|
||||
return []
|
||||
@@ -40,14 +37,19 @@ def _generate_layouts(keyboard):
|
||||
row, col = key_data['matrix']
|
||||
identifier = f'k{ROW_LETTERS[row]}{COL_LETTERS[col]}'
|
||||
|
||||
try:
|
||||
layout_matrix[row][col] = identifier
|
||||
layout_keys.append(identifier)
|
||||
except IndexError:
|
||||
if row >= row_num or col >= col_num:
|
||||
key_name = key_data.get('label', identifier)
|
||||
cli.log.error(f'{keyboard}/{layout_name}: Matrix data out of bounds at index {index} ({key_name}): [{row}, {col}]')
|
||||
if row >= row_num:
|
||||
cli.log.error(f'{keyboard}/{layout_name}: Matrix row for key {index} ({key_name}) is {row} but must be less than {row_num}')
|
||||
|
||||
if col >= col_num:
|
||||
cli.log.error(f'{keyboard}/{layout_name}: Matrix column for key {index} ({key_name}) is {col} but must be less than {col_num}')
|
||||
|
||||
return []
|
||||
|
||||
layout_matrix[row][col] = identifier
|
||||
layout_keys.append(identifier)
|
||||
|
||||
lines.append('')
|
||||
lines.append(f'#define {layout_name}({", ".join(layout_keys)}) {{ \\')
|
||||
|
||||
@@ -65,6 +67,32 @@ def _generate_layouts(keyboard):
|
||||
return lines
|
||||
|
||||
|
||||
def _generate_keycodes(kb_info_json):
|
||||
"""Generates keyboard level keycodes.
|
||||
"""
|
||||
if 'keycodes' not in kb_info_json:
|
||||
return []
|
||||
|
||||
lines = []
|
||||
lines.append('enum keyboard_keycodes {')
|
||||
|
||||
for index, item in enumerate(kb_info_json.get('keycodes')):
|
||||
key = item["key"]
|
||||
if index == 0:
|
||||
lines.append(f' {key} = QK_KB_0,')
|
||||
else:
|
||||
lines.append(f' {key},')
|
||||
|
||||
lines.append('};')
|
||||
|
||||
for item in kb_info_json.get('keycodes', []):
|
||||
key = item["key"]
|
||||
for alias in item.get("aliases", []):
|
||||
lines.append(f'#define {alias} {key}')
|
||||
|
||||
return lines
|
||||
|
||||
|
||||
@cli.argument('-i', '--include', nargs='?', arg_only=True, help='Optional file to include')
|
||||
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||
@@ -73,8 +101,12 @@ def _generate_layouts(keyboard):
|
||||
def generate_keyboard_h(cli):
|
||||
"""Generates the keyboard.h file.
|
||||
"""
|
||||
# Build the info.json file
|
||||
kb_info_json = info_json(cli.args.keyboard)
|
||||
|
||||
keyboard_h = cli.args.include
|
||||
dd_layouts = _generate_layouts(cli.args.keyboard)
|
||||
dd_layouts = _generate_layouts(cli.args.keyboard, kb_info_json)
|
||||
dd_keycodes = _generate_keycodes(kb_info_json)
|
||||
valid_config = dd_layouts or keyboard_h
|
||||
|
||||
# Build the layouts.h file.
|
||||
@@ -87,6 +119,11 @@ def generate_keyboard_h(cli):
|
||||
if keyboard_h:
|
||||
keyboard_h_lines.append(f'#include "{Path(keyboard_h).name}"')
|
||||
|
||||
keyboard_h_lines.append('')
|
||||
keyboard_h_lines.append('// Keycode content')
|
||||
if dd_keycodes:
|
||||
keyboard_h_lines.extend(dd_keycodes)
|
||||
|
||||
# Protect against poorly configured keyboards
|
||||
if not valid_config:
|
||||
keyboard_h_lines.append('#error("<keyboard>.h is required unless your keyboard uses data-driven configuration. Please rename your keyboard\'s header file to <keyboard>.h")')
|
||||
|
||||
@@ -96,6 +96,11 @@ def _generate_helpers(lines, keycodes):
|
||||
|
||||
|
||||
def _generate_aliases(lines, keycodes):
|
||||
# Work around ChibiOS ch.h include guard
|
||||
if 'CH_H' in [value['key'] for value in keycodes['aliases'].values()]:
|
||||
lines.append('')
|
||||
lines.append('#undef CH_H')
|
||||
|
||||
lines.append('')
|
||||
lines.append('// Aliases')
|
||||
for key, value in keycodes["aliases"].items():
|
||||
@@ -143,7 +148,7 @@ def generate_keycode_extras(cli):
|
||||
"""
|
||||
|
||||
# Build the header file.
|
||||
keycodes_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', '#include "keymap.h"', '// clang-format off']
|
||||
keycodes_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', '#include "keycodes.h"', '// clang-format off']
|
||||
|
||||
keycodes = load_spec(cli.args.version, cli.args.lang)
|
||||
|
||||
|
||||
55
lib/python/qmk/cli/generate/make_dependencies.py
Executable file
55
lib/python/qmk/cli/generate/make_dependencies.py
Executable file
@@ -0,0 +1,55 @@
|
||||
"""Used by the make system to generate dependency lists for each of the generated files.
|
||||
"""
|
||||
from pathlib import Path
|
||||
from milc import cli
|
||||
|
||||
from argcomplete.completers import FilesCompleter
|
||||
|
||||
from qmk.commands import dump_lines
|
||||
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||
from qmk.keymap import keymap_completer, locate_keymap
|
||||
from qmk.path import normpath, FileType
|
||||
|
||||
|
||||
@cli.argument('filename', nargs='?', arg_only=True, type=FileType('r'), completer=FilesCompleter('.json'), help='A configurator export JSON.')
|
||||
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, required=True, help='Keyboard to generate dependency file for.')
|
||||
@cli.argument('-km', '--keymap', completer=keymap_completer, help='The keymap to build a firmware for. Ignored when a configurator export is supplied.')
|
||||
@cli.subcommand('Generates the list of dependencies associated with a keyboard build and its generated files.', hidden=True)
|
||||
def generate_make_dependencies(cli):
|
||||
"""Generates the list of dependent info.json, rules.mk, and config.h files for a keyboard.
|
||||
"""
|
||||
interesting_files = [
|
||||
'info.json',
|
||||
'rules.mk',
|
||||
'post_rules.mk',
|
||||
'config.h',
|
||||
'post_config.h',
|
||||
]
|
||||
|
||||
check_files = []
|
||||
|
||||
# Walk up the keyboard's directory tree looking for the files we're interested in
|
||||
keyboards_root = Path('keyboards')
|
||||
parent_path = Path('keyboards') / cli.args.keyboard
|
||||
while parent_path != keyboards_root:
|
||||
for file in interesting_files:
|
||||
check_files.append(parent_path / file)
|
||||
parent_path = parent_path.parent
|
||||
|
||||
# Find the keymap and include any of the interesting files
|
||||
if cli.args.keymap is not None:
|
||||
km = locate_keymap(cli.args.keyboard, cli.args.keymap)
|
||||
if km is not None:
|
||||
# keymap.json is only valid for the keymap, so check this one separately
|
||||
check_files.append(km.parent / 'keymap.json')
|
||||
# Add all the interesting files
|
||||
for file in interesting_files:
|
||||
check_files.append(km.parent / file)
|
||||
|
||||
# If we have a matching userspace, include those too
|
||||
for file in interesting_files:
|
||||
check_files.append(Path('users') / cli.args.keymap / file)
|
||||
|
||||
dump_lines(cli.args.output, [f'generated-files: $(wildcard {found})\n' for found in check_files])
|
||||
@@ -7,14 +7,21 @@ from qmk import submodules
|
||||
|
||||
REMOVE_DIRS = [
|
||||
'lib/ugfx',
|
||||
'lib/pico-sdk',
|
||||
'lib/chibios-contrib/ext/mcux-sdk',
|
||||
'lib/lvgl',
|
||||
]
|
||||
|
||||
IGNORE_DIRS = [
|
||||
'lib/arm_atsam',
|
||||
'lib/fnv',
|
||||
'lib/lib8tion',
|
||||
'lib/python',
|
||||
'lib/usbhost',
|
||||
]
|
||||
|
||||
|
||||
@cli.argument('--check', arg_only=True, action='store_true', help='Check if the submodules are dirty, and display a warning if they are.')
|
||||
@cli.argument('--sync', arg_only=True, action='store_true', help='Shallow clone any missing submodules.')
|
||||
@cli.argument('-f', '--force', action='store_true', help='Flag to remove unexpected directories')
|
||||
@cli.subcommand('Git Submodule actions.')
|
||||
def git_submodule(cli):
|
||||
"""Git Submodule actions
|
||||
@@ -29,7 +36,15 @@ def git_submodule(cli):
|
||||
cli.run(['git', 'submodule', 'update', '--depth=50', '--init', name], capture_output=False)
|
||||
return True
|
||||
|
||||
for folder in REMOVE_DIRS:
|
||||
# can be the default behavior with: qmk config git_submodule.force=True
|
||||
remove_dirs = REMOVE_DIRS
|
||||
if cli.config.git_submodule.force:
|
||||
# Also trash everything that isnt marked as "safe"
|
||||
for path in normpath('lib').iterdir():
|
||||
if not any(ignore in path.as_posix() for ignore in IGNORE_DIRS):
|
||||
remove_dirs.append(path)
|
||||
|
||||
for folder in map(normpath, remove_dirs):
|
||||
if normpath(folder).is_dir():
|
||||
print(f"Removing '{folder}'")
|
||||
shutil.rmtree(folder)
|
||||
|
||||
@@ -18,6 +18,33 @@ from qmk.path import is_keyboard
|
||||
UNICODE_SUPPORT = sys.stdout.encoding.lower().startswith('utf')
|
||||
|
||||
|
||||
def _strip_api_content(info_json):
|
||||
# Ideally this would only be added in the API pathway.
|
||||
info_json.pop('platform', None)
|
||||
info_json.pop('platform_key', None)
|
||||
info_json.pop('processor_type', None)
|
||||
info_json.pop('protocol', None)
|
||||
info_json.pop('config_h_features', None)
|
||||
info_json.pop('keymaps', None)
|
||||
info_json.pop('keyboard_folder', None)
|
||||
info_json.pop('parse_errors', None)
|
||||
info_json.pop('parse_warnings', None)
|
||||
|
||||
for layout in info_json.get('layouts', {}).values():
|
||||
layout.pop('filename', None)
|
||||
layout.pop('c_macro', None)
|
||||
layout.pop('json_layout', None)
|
||||
|
||||
if 'matrix_pins' in info_json:
|
||||
info_json.pop('matrix_size', None)
|
||||
|
||||
for feature in ['rgb_matrix', 'led_matrix']:
|
||||
if info_json.get(feature, {}).get("layout", None):
|
||||
info_json[feature].pop('led_count', None)
|
||||
|
||||
return info_json
|
||||
|
||||
|
||||
def show_keymap(kb_info_json, title_caps=True):
|
||||
"""Render the keymap in ascii art.
|
||||
"""
|
||||
@@ -81,7 +108,6 @@ def print_friendly_output(kb_info_json):
|
||||
cli.echo('{fg_blue}Maintainer{fg_reset}: QMK Community')
|
||||
else:
|
||||
cli.echo('{fg_blue}Maintainer{fg_reset}: %s', kb_info_json['maintainer'])
|
||||
cli.echo('{fg_blue}Keyboard Folder{fg_reset}: %s', kb_info_json.get('keyboard_folder', 'Unknown'))
|
||||
cli.echo('{fg_blue}Layouts{fg_reset}: %s', ', '.join(sorted(kb_info_json['layouts'].keys())))
|
||||
cli.echo('{fg_blue}Processor{fg_reset}: %s', kb_info_json.get('processor', 'Unknown'))
|
||||
cli.echo('{fg_blue}Bootloader{fg_reset}: %s', kb_info_json.get('bootloader', 'Unknown'))
|
||||
@@ -141,6 +167,7 @@ def print_parsed_rules_mk(keyboard_name):
|
||||
@cli.argument('-f', '--format', default='friendly', arg_only=True, help='Format to display the data in (friendly, text, json) (Default: friendly).')
|
||||
@cli.argument('--ascii', action='store_true', default=not UNICODE_SUPPORT, help='Render layout box drawings in ASCII only.')
|
||||
@cli.argument('-r', '--rules-mk', action='store_true', help='Render the parsed values of the keyboard\'s rules.mk file.')
|
||||
@cli.argument('-a', '--api', action='store_true', help='Show fully processed info intended for API consumption.')
|
||||
@cli.subcommand('Keyboard information.')
|
||||
@automagic_keyboard
|
||||
@automagic_keymap
|
||||
@@ -171,9 +198,12 @@ def info(cli):
|
||||
else:
|
||||
kb_info_json = info_json(cli.config.info.keyboard)
|
||||
|
||||
if not cli.args.api:
|
||||
kb_info_json = _strip_api_content(kb_info_json)
|
||||
|
||||
# Output in the requested format
|
||||
if cli.args.format == 'json':
|
||||
print(json.dumps(kb_info_json, cls=InfoJSONEncoder))
|
||||
print(json.dumps(kb_info_json, cls=InfoJSONEncoder, sort_keys=True))
|
||||
return True
|
||||
elif cli.args.format == 'text':
|
||||
print_dotted_output(kb_info_json)
|
||||
|
||||
@@ -5,7 +5,7 @@ from milc import cli
|
||||
|
||||
import qmk.keymap
|
||||
import qmk.path
|
||||
from qmk.commands import parse_configurator_json
|
||||
from qmk.commands import dump_lines, parse_configurator_json
|
||||
|
||||
|
||||
@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
|
||||
@@ -21,21 +21,8 @@ def json2c(cli):
|
||||
# Parse the configurator from json file (or stdin)
|
||||
user_keymap = parse_configurator_json(cli.args.filename)
|
||||
|
||||
# Environment processing
|
||||
if cli.args.output and cli.args.output.name == '-':
|
||||
cli.args.output = None
|
||||
|
||||
# Generate the keymap
|
||||
keymap_c = qmk.keymap.generate_c(user_keymap)
|
||||
|
||||
if cli.args.output:
|
||||
cli.args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
if cli.args.output.exists():
|
||||
cli.args.output.replace(cli.args.output.parent / (cli.args.output.name + '.bak'))
|
||||
cli.args.output.write_text(keymap_c)
|
||||
|
||||
if not cli.args.quiet:
|
||||
cli.log.info('Wrote keymap to %s.', cli.args.output)
|
||||
|
||||
else:
|
||||
print(keymap_c)
|
||||
# Show the results
|
||||
dump_lines(cli.args.output, keymap_c.split('\n'), cli.args.quiet)
|
||||
|
||||
@@ -2,54 +2,18 @@
|
||||
|
||||
This will compile everything in parallel, for testing purposes.
|
||||
"""
|
||||
import fnmatch
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
from subprocess import DEVNULL
|
||||
from dotty_dict import dotty
|
||||
from milc import cli
|
||||
|
||||
from qmk.constants import QMK_FIRMWARE
|
||||
from qmk.commands import _find_make, get_make_parallel_args
|
||||
from qmk.info import keymap_json
|
||||
import qmk.keyboard
|
||||
import qmk.keymap
|
||||
|
||||
|
||||
def _set_log_level(level):
|
||||
cli.acquire_lock()
|
||||
old = cli.log_level
|
||||
cli.log_level = level
|
||||
cli.log.setLevel(level)
|
||||
logging.root.setLevel(level)
|
||||
cli.release_lock()
|
||||
return old
|
||||
|
||||
|
||||
def _all_keymaps(keyboard):
|
||||
old = _set_log_level(logging.CRITICAL)
|
||||
keymaps = qmk.keymap.list_keymaps(keyboard)
|
||||
_set_log_level(old)
|
||||
return (keyboard, keymaps)
|
||||
|
||||
|
||||
def _keymap_exists(keyboard, keymap):
|
||||
old = _set_log_level(logging.CRITICAL)
|
||||
ret = keyboard if qmk.keymap.locate_keymap(keyboard, keymap) is not None else None
|
||||
_set_log_level(old)
|
||||
return ret
|
||||
|
||||
|
||||
def _load_keymap_info(keyboard, keymap):
|
||||
old = _set_log_level(logging.CRITICAL)
|
||||
ret = (keyboard, keymap, keymap_json(keyboard, keymap))
|
||||
_set_log_level(old)
|
||||
return ret
|
||||
from qmk.keyboard import resolve_keyboard
|
||||
from qmk.search import search_keymap_targets
|
||||
|
||||
|
||||
@cli.argument('builds', nargs='*', arg_only=True, help="List of builds in form <keyboard>:<keymap> to compile in parallel. Specifying this overrides all other target search options.")
|
||||
@cli.argument('-t', '--no-temp', arg_only=True, action='store_true', help="Remove temporary files during build.")
|
||||
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs; 0 means unlimited.")
|
||||
@cli.argument('-c', '--clean', arg_only=True, action='store_true', help="Remove object files before compiling.")
|
||||
@@ -75,55 +39,10 @@ def mass_compile(cli):
|
||||
builddir = Path(QMK_FIRMWARE) / '.build'
|
||||
makefile = builddir / 'parallel_kb_builds.mk'
|
||||
|
||||
targets = []
|
||||
|
||||
with multiprocessing.Pool() as pool:
|
||||
cli.log.info(f'Retrieving list of keyboards with keymap "{cli.args.keymap}"...')
|
||||
target_list = []
|
||||
if cli.args.keymap == 'all':
|
||||
kb_to_kms = pool.map(_all_keymaps, qmk.keyboard.list_keyboards())
|
||||
for targets in kb_to_kms:
|
||||
keyboard = targets[0]
|
||||
keymaps = targets[1]
|
||||
target_list.extend([(keyboard, keymap) for keymap in keymaps])
|
||||
else:
|
||||
target_list = [(kb, cli.args.keymap) for kb in filter(lambda kb: kb is not None, pool.starmap(_keymap_exists, [(kb, cli.args.keymap) for kb in qmk.keyboard.list_keyboards()]))]
|
||||
|
||||
if len(cli.args.filter) == 0:
|
||||
targets = target_list
|
||||
else:
|
||||
cli.log.info('Parsing data for all matching keyboard/keymap combinations...')
|
||||
valid_keymaps = [(e[0], e[1], dotty(e[2])) for e in pool.starmap(_load_keymap_info, target_list)]
|
||||
|
||||
equals_re = re.compile(r'^(?P<key>[a-zA-Z0-9_\.]+)\s*=\s*(?P<value>[^#]+)$')
|
||||
exists_re = re.compile(r'^exists\((?P<key>[a-zA-Z0-9_\.]+)\)$')
|
||||
for filter_txt in cli.args.filter:
|
||||
f = equals_re.match(filter_txt)
|
||||
if f is not None:
|
||||
key = f.group('key')
|
||||
value = f.group('value')
|
||||
cli.log.info(f'Filtering on condition ("{key}" == "{value}")...')
|
||||
|
||||
def _make_filter(k, v):
|
||||
expr = fnmatch.translate(v)
|
||||
rule = re.compile(expr, re.IGNORECASE)
|
||||
|
||||
def f(e):
|
||||
lhs = e[2].get(k)
|
||||
lhs = str(False if lhs is None else lhs)
|
||||
return rule.search(lhs) is not None
|
||||
|
||||
return f
|
||||
|
||||
valid_keymaps = filter(_make_filter(key, value), valid_keymaps)
|
||||
|
||||
f = exists_re.match(filter_txt)
|
||||
if f is not None:
|
||||
key = f.group('key')
|
||||
cli.log.info(f'Filtering on condition (exists: "{key}")...')
|
||||
valid_keymaps = filter(lambda e: e[2].get(key) is not None, valid_keymaps)
|
||||
|
||||
targets = [(e[0], e[1]) for e in valid_keymaps]
|
||||
if len(cli.args.builds) > 0:
|
||||
targets = list(sorted(set([(resolve_keyboard(e[0]), e[1]) for e in [b.split(':') for b in cli.args.builds]])))
|
||||
else:
|
||||
targets = search_keymap_targets(cli.args.keymap, cli.args.filter)
|
||||
|
||||
if len(targets) == 0:
|
||||
return
|
||||
@@ -134,20 +53,22 @@ def mass_compile(cli):
|
||||
keyboard_name = target[0]
|
||||
keymap_name = target[1]
|
||||
keyboard_safe = keyboard_name.replace('/', '_')
|
||||
build_log = f"{QMK_FIRMWARE}/.build/build.log.{os.getpid()}.{keyboard_safe}.{keymap_name}"
|
||||
failed_log = f"{QMK_FIRMWARE}/.build/failed.log.{os.getpid()}.{keyboard_safe}.{keymap_name}"
|
||||
# yapf: disable
|
||||
f.write(
|
||||
f"""\
|
||||
all: {keyboard_safe}_{keymap_name}_binary
|
||||
{keyboard_safe}_{keymap_name}_binary:
|
||||
@rm -f "{QMK_FIRMWARE}/.build/failed.log.{keyboard_safe}.{keymap_name}" || true
|
||||
@echo "Compiling QMK Firmware for target: '{keyboard_name}:{keymap_name}'..." >>"{QMK_FIRMWARE}/.build/build.log.{os.getpid()}.{keyboard_safe}"
|
||||
@rm -f "{build_log}" || true
|
||||
@echo "Compiling QMK Firmware for target: '{keyboard_name}:{keymap_name}'..." >>"{build_log}"
|
||||
+@$(MAKE) -C "{QMK_FIRMWARE}" -f "{QMK_FIRMWARE}/builddefs/build_keyboard.mk" KEYBOARD="{keyboard_name}" KEYMAP="{keymap_name}" COLOR=true SILENT=false {' '.join(cli.args.env)} \\
|
||||
>>"{QMK_FIRMWARE}/.build/build.log.{os.getpid()}.{keyboard_safe}.{keymap_name}" 2>&1 \\
|
||||
|| cp "{QMK_FIRMWARE}/.build/build.log.{os.getpid()}.{keyboard_safe}.{keymap_name}" "{QMK_FIRMWARE}/.build/failed.log.{os.getpid()}.{keyboard_safe}.{keymap_name}"
|
||||
@{{ grep '\[ERRORS\]' "{QMK_FIRMWARE}/.build/build.log.{os.getpid()}.{keyboard_safe}.{keymap_name}" >/dev/null 2>&1 && printf "Build %-64s \e[1;31m[ERRORS]\e[0m\\n" "{keyboard_name}:{keymap_name}" ; }} \\
|
||||
|| {{ grep '\[WARNINGS\]' "{QMK_FIRMWARE}/.build/build.log.{os.getpid()}.{keyboard_safe}.{keymap_name}" >/dev/null 2>&1 && printf "Build %-64s \e[1;33m[WARNINGS]\e[0m\\n" "{keyboard_name}:{keymap_name}" ; }} \\
|
||||
>>"{build_log}" 2>&1 \\
|
||||
|| cp "{build_log}" "{failed_log}"
|
||||
@{{ grep '\[ERRORS\]' "{build_log}" >/dev/null 2>&1 && printf "Build %-64s \e[1;31m[ERRORS]\e[0m\\n" "{keyboard_name}:{keymap_name}" ; }} \\
|
||||
|| {{ grep '\[WARNINGS\]' "{build_log}" >/dev/null 2>&1 && printf "Build %-64s \e[1;33m[WARNINGS]\e[0m\\n" "{keyboard_name}:{keymap_name}" ; }} \\
|
||||
|| printf "Build %-64s \e[1;32m[OK]\e[0m\\n" "{keyboard_name}:{keymap_name}"
|
||||
@rm -f "{QMK_FIRMWARE}/.build/build.log.{os.getpid()}.{keyboard_safe}.{keymap_name}" || true
|
||||
@rm -f "{build_log}" || true
|
||||
"""# noqa
|
||||
)
|
||||
# yapf: enable
|
||||
@@ -158,10 +79,6 @@ all: {keyboard_safe}_{keymap_name}_binary
|
||||
f"""\
|
||||
@rm -rf "{QMK_FIRMWARE}/.build/{keyboard_safe}_{keymap_name}.elf" 2>/dev/null || true
|
||||
@rm -rf "{QMK_FIRMWARE}/.build/{keyboard_safe}_{keymap_name}.map" 2>/dev/null || true
|
||||
@rm -rf "{QMK_FIRMWARE}/.build/{keyboard_safe}_{keymap_name}.hex" 2>/dev/null || true
|
||||
@rm -rf "{QMK_FIRMWARE}/.build/{keyboard_safe}_{keymap_name}.bin" 2>/dev/null || true
|
||||
@rm -rf "{QMK_FIRMWARE}/.build/{keyboard_safe}_{keymap_name}.uf2" 2>/dev/null || true
|
||||
@rm -rf "{QMK_FIRMWARE}/.build/obj_{keyboard_safe}" || true
|
||||
@rm -rf "{QMK_FIRMWARE}/.build/obj_{keyboard_safe}_{keymap_name}" || true
|
||||
"""# noqa
|
||||
)
|
||||
|
||||
@@ -75,7 +75,7 @@ def migrate(cli):
|
||||
|
||||
# Finally write out updated info.json
|
||||
cli.log.info(f' Updating {target_info}')
|
||||
target_info.write_text(json.dumps(info_data.to_dict(), cls=InfoJSONEncoder))
|
||||
target_info.write_text(json.dumps(info_data.to_dict(), cls=InfoJSONEncoder, sort_keys=True))
|
||||
|
||||
cli.log.info(f'{{fg_green}}Migration of keyboard {{fg_cyan}}{cli.args.keyboard}{{fg_green}} complete!{{fg_reset}}')
|
||||
cli.log.info(f"Verify build with {{fg_yellow}}qmk compile -kb {cli.args.keyboard} -km default{{fg_reset}}.")
|
||||
|
||||
@@ -102,7 +102,7 @@ def augment_community_info(src, dest):
|
||||
item["matrix"] = [int(item["y"]), int(item["x"])]
|
||||
|
||||
# finally write out the updated info.json
|
||||
dest.write_text(json.dumps(info, cls=InfoJSONEncoder))
|
||||
dest.write_text(json.dumps(info, cls=InfoJSONEncoder, sort_keys=True))
|
||||
|
||||
|
||||
def _question(*args, **kwargs):
|
||||
|
||||
@@ -5,7 +5,7 @@ import shutil
|
||||
from milc import cli
|
||||
from milc.questions import question
|
||||
|
||||
from qmk.path import is_keyboard, keymap
|
||||
from qmk.path import is_keyboard, keymaps, keymap
|
||||
from qmk.git import git_get_username
|
||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||
@@ -50,9 +50,9 @@ def new_keymap(cli):
|
||||
return False
|
||||
|
||||
# generate keymap paths
|
||||
km_path = keymap(kb_name)
|
||||
keymap_path_default = km_path / 'default'
|
||||
keymap_path_new = km_path / user_name
|
||||
keymaps_dirs = keymaps(kb_name)
|
||||
keymap_path_default = keymap(kb_name, 'default')
|
||||
keymap_path_new = keymaps_dirs[0] / user_name
|
||||
|
||||
if not keymap_path_default.exists():
|
||||
cli.log.error(f'Default keymap {{fg_cyan}}{keymap_path_default}{{fg_reset}} does not exist!')
|
||||
|
||||
@@ -141,5 +141,5 @@ def via2json(cli):
|
||||
# Generate the keymap.json
|
||||
keymap_json = generate_json(cli.args.keymap, cli.args.keyboard, keymap_layout, keymap_data, macro_data)
|
||||
|
||||
keymap_lines = [json.dumps(keymap_json, cls=KeymapJSONEncoder)]
|
||||
keymap_lines = [json.dumps(keymap_json, cls=KeymapJSONEncoder, sort_keys=True)]
|
||||
dump_lines(cli.args.output, keymap_lines, cli.args.quiet)
|
||||
|
||||
Reference in New Issue
Block a user