Add support for qmk_configurator style aliases (#11954)

* Add support for qmk_configurator style aliases

* add the keyboard aliases to the api data

* add support for a keyboard metadata file

* make flake8 happy
This commit is contained in:
Zach White 2021-03-24 09:26:38 -07:00 committed by GitHub
parent 723d9af04d
commit 299008be36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 614 additions and 106 deletions

View File

@ -0,0 +1,443 @@
{
# Format for each entry:
# <alias>: {
# target: <keyboard_folder>,
# layouts: {
# <layout_alias>: <layout_target>
# }
# }
#
# Both target and layouts are optional.
'2_milk': {
target: 'spaceman/2_milk'
},
'aeboards/ext65': {
target: 'aeboards/ext65/rev1'
},
'ai03/equinox': {
target: 'ai03/equinox/rev1'
},
aleth42: {
target: 'aleth42/rev1'
},
alice: {
target: 'tgr/alice'
},
angel17: {
target: 'angel17/alpha'
},
angel64: {
target: 'angel64/alpha'
},
at101_blackheart: {
target: 'at101_bh'
},
'atom47/rev2': {
target: 'maartenwut/atom47/rev2'
},
'atom47/rev3': {
target: 'maartenwut/atom47/rev3'
},
bear_face: {
target: 'bear_face/v1'
},
'bpiphany/pegasushoof': {
target: 'bpiphany/pegasushoof/2013'
},
chavdai40: {
target: 'chavdai40/rev1'
},
'candybar/lefty': {
target: 'tkc/candybar/lefty'
},
'candybar/righty': {
target: 'tkc/candybar/righty'
},
canoe: {
target: 'percent/canoe'
},
'cmm_studio/saka68': {
target: 'cmm_studio/saka68/solder'
},
'crkbd/rev1': {
target: 'crkbd/rev1/legacy'
},
'doro67/multi': {
layouts: {
LAYOUT_ansi: 'LAYOUT_65_ansi_blocker'
}
},
'doro67/regular': {
layouts: {
LAYOUT: 'LAYOUT_65_ansi_blocker'
}
},
'doro67/rgb': {
layouts: {
LAYOUT: 'LAYOUT_65_ansi_blocker'
}
},
drakon: {
target: 'jagdpietr/drakon'
},
'dztech/dz60rgb': {
target: 'dztech/dz60rgb/v1'
},
'dztech/dz60rgb_ansi': {
target: 'dztech/dz60rgb_ansi/v1'
},
'dztech/dz60rgb_wkl': {
target: 'dztech/dz60rgb_wkl/v1'
},
'dztech/dz65rgb': {
target: 'dztech/dz65rgb/v1'
},
eek: {
target: 'eek/silk_down'
},
ergoinu: {
target: 'dm9records/ergoinu'
},
'exclusive/e85': {
target: 'exclusive/e85/hotswap'
},
gh60: {
target: 'gh60/revc'
},
'handwired/ferris': {
target: 'ferris/0_1'
},
'helix/pico/sc/back': {
target: 'helix/pico/sc'
},
'helix/pico/sc/under': {
target: 'helix/pico/sc'
},
'helix/rev2/back/oled': {
target: 'helix/rev2/back'
},
'helix/rev2/oled': {
target: 'helix/rev2'
},
'helix/rev2/oled/back': {
target: 'helix/rev2/back'
},
'helix/rev2/oled/under': {
target: 'helix/rev2/under'
},
'helix/rev2/sc/back': {
target: 'helix/rev2/sc'
},
'helix/rev2/sc/oled': {
target: 'helix/rev2/sc'
},
'helix/rev2/sc/oledback': {
target: 'helix/rev2/sc'
},
'helix/rev2/sc/oledunder': {
target: 'helix/rev2/sc'
},
'helix/rev2/sc/under': {
target: 'helix/rev2/sc'
},
'helix/rev2/under': {
target: 'helix/rev2/sc'
},
'helix/rev2/under/oled': {
target: 'helix/rev2/under'
},
id80: {
target: 'id80/ansi'
},
idb_60: {
target: 'idb/idb_60',
layouts: {
LAYOUT: 'LAYOUT_all'
}
},
jones: {
target: 'jones/v03_1'
},
katana60: {
target: 'rominronin/katana60/rev1'
},
'kbdfans/kbd67mkiirgb': {
target: 'kbdfans/kbd67/mkiirgb',
layouts: {
LAYOUT: 'LAYOUT_65_ansi_blocker'
}
},
'kbdfans/kbd67/mkiirgb': {
target: 'kbdfans/kbd67/mkiirgb/v1'
},
'keebio/dsp40': {
target: 'keebio/dsp40/rev1'
},
'keycapsss/plaid_pad': {
target: 'keycapsss/plaid_pad/rev1'
},
kudox: {
target: 'kudox/rev1'
},
'lfkeyboards/lfk78': {
target: 'lfkeyboards/lfk78/revj'
},
'lfkeyboards/smk65': {
target: 'lfkeyboards/smk65/revb'
},
'maartenwut/atom47/rev2': {
target: 'evyd13/atom47/rev2'
},
'maartenwut/atom47/rev3': {
target: 'evyd13/atom47/rev3'
},
'maartenwut/eon40': {
target: 'evyd13/eon40'
},
'maartenwut/eon65': {
target: 'evyd13/eon65'
},
'maartenwut/eon75': {
target: 'evyd13/eon75'
},
'maartenwut/eon87': {
target: 'evyd13/eon87'
},
'maartenwut/eon95': {
target: 'evyd13/eon95'
},
'maartenwut/gh80_1800': {
target: 'evyd13/gh80_1800'
},
'maartenwut/gh80_3700': {
target: 'evyd13/gh80_3700'
},
'maartenwut/minitomic': {
target: 'evyd13/minitomic'
},
'maartenwut/mx5160': {
target: 'evyd13/mx5160'
},
'maartenwut/nt660': {
target: 'evyd13/nt660'
},
'maartenwut/omrontkl': {
target: 'evyd13/omrontkl'
},
'maartenwut/plain60': {
target: 'evyd13/plain60'
},
'maartenwut/pockettype': {
target: 'evyd13/pockettype'
},
'maartenwut/quackfire': {
target: 'evyd13/quackfire'
},
'maartenwut/solheim68': {
target: 'evyd13/solheim68'
},
'maartenwut/ta65': {
target: 'evyd13/ta65'
},
'maartenwut/wasdat': {
target: 'evyd13/wasdat'
},
'maartenwut/wasdat_code': {
target: 'evyd13/wasdat_code'
},
'maartenwut/wonderland': {
target: 'evyd13/wonderland'
},
'mechlovin/hannah910': {
target: 'mechlovin/hannah910/rev1'
},
'mechlovin/adelais/rgb_led': {
target: 'mechlovin/adelais/rgb_led/rev1'
},
'mechlovin/adelais/standard_led': {
target: 'mechlovin/adelais/standard_led/rev2'
},
'mechlovin/delphine': {
target: 'mechlovin/delphine/mono_led'
},
'mechlovin/hannah60rgb': {
target: 'mechlovin/hannah60rgb/rev1'
},
'melgeek/z70ultra': {
target: 'melgeek/z70ultra/rev1'
},
'mechlovin/hannah65': {
target: 'mechlovin/hannah65/rev1'
},
model01: {
target: 'keyboardio/model01'
},
m0lly: {
target: 'tkc/m0lly'
},
'montsinger/rebound': {
target: 'montsinger/rebound/rev1'
},
nomu30: {
target: 'nomu30/rev1'
},
'noxary/268_2': {
layouts: {
LAYOUT: 'LAYOUT_65_ansi_blocker'
}
},
oddball: {
target: 'oddball/v1'
},
omnikey_blackheart: {
target: 'omnikey_bh'
},
'pabile/p20': {
target: 'pabile/p20/ver1'
},
'pancake/feather': {
target: 'spaceman/pancake/feather'
},
'pancake/promicro': {
target: 'spaceman/pancake/promicro'
},
'percent/canoe': {
layouts: {
LAYOUT_iso: 'LAYOUT_65_iso_blocker'
}
},
plaid: {
target: 'dm9records/plaid'
},
plain60: {
target: 'maartenwut/plain60'
},
'ploopyco/trackball': {
target: 'ploopyco/trackball/rev1_005'
},
polilla: {
target: 'polilla/rev1'
},
'preonic/rev1': {
layouts: {
LAYOUT_preonic_grid: 'LAYOUT_ortho_5x12'
}
},
'preonic/rev2': {
layouts: {
LAYOUT_preonic_grid: 'LAYOUT_ortho_5x12'
}
},
'preonic/rev3': {
layouts: {
LAYOUT_preonic_grid: 'LAYOUT_ortho_5x12'
}
},
'primekb/prime_l': {
target: 'primekb/prime_l/v1'
},
'primekb/prime_l_v2': {
target: 'primekb/prime_l/v2'
},
'projectkb/alice': {
target: 'projectkb/alice/rev1'
},
'rama/koyu': {
target: 'wilba_tech/rama_works_koyu'
},
'rama/m6_a': {
target: 'wilba_tech/rama_works_m6_a'
},
'rama/m6_b': {
target: 'wilba_tech/rama_works_m6_b'
},
'rama/m10_b': {
target: 'wilba_tech/rama_works_m10_b'
},
'rama/m60_a': {
target: 'wilba_tech/rama_works_m60_a'
},
'rama/u80_a': {
target: 'wilba_tech/rama_works_u80_a'
},
'ramonimbao/herringbone': {
target: 'ramonimbao/herringbone/v1'
},
'rgbkb/pan': {
target: 'rgbkb/pan/rev1/32a'
},
'rgbkb/pan/rev1': {
target: 'rgbkb/pan/rev1/32a'
},
romac: {
target: 'kingly_keys/romac'
},
ropro: {
target: 'kingly_keys/ropro'
},
satan: {
target: 'gh60/satan'
},
skog: {
target: 'percent/skog'
},
speedo: {
target: 'cozykeys/speedo/v2'
},
stoutgat: {
target: 'tkw/stoutgat/v1'
},
suihankey: {
target: 'suihankey/split/alpha'
},
ta65: {
target: 'maartenwut/ta65'
},
tartan: {
target: 'dm9records/tartan'
},
tkc1800: {
target: 'tkc/tkc1800'
},
'tkw/stoutgat/v2': {
target: 'tkw/stoutgat/v2/f411'
},
underscore33: {
target: 'underscore33/rev1'
},
vinta: {
layouts: {
LAYOUT_67_ansi: 'LAYOUT_65_ansi_blocker'
}
},
wasdat: {
target: 'maartenwut/wasdat'
},
'westfoxtrot/cypher': {
target: 'westfoxtrot/cypher/rev1'
},
'whale/sk': {
target: 'whale/sk/v3'
},
'xelus/dawn60': {
target: 'xelus/dawn60/rev1'
},
'xelus/valor': {
target: 'xelus/valor/rev1'
},
yd60mq: {
target: 'yd60mq/12led'
},
ymd75: {
target: 'ymd75/rev1'
},
z150_blackheart: {
target: 'z150_bh'
},
zeal60: {
target: 'wilba_tech/zeal60'
},
zeal65: {
target: 'wilba_tech/zeal65'
}
}

View File

@ -7,12 +7,13 @@ from milc import cli
import qmk.keymap import qmk.keymap
import qmk.path import qmk.path
from qmk.info_json_encoder import InfoJSONEncoder from qmk.info_json_encoder import InfoJSONEncoder
from qmk.keyboard import keyboard_folder
@cli.argument('--no-cpp', arg_only=True, action='store_false', help='Do not use \'cpp\' on keymap.c') @cli.argument('--no-cpp', arg_only=True, action='store_false', help='Do not use \'cpp\' on keymap.c')
@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') @cli.argument('-o', '--output', arg_only=True, type=qmk.path.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('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
@cli.argument('-kb', '--keyboard', arg_only=True, required=True, help='The keyboard\'s name') @cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, required=True, help='The keyboard\'s name')
@cli.argument('-km', '--keymap', arg_only=True, required=True, help='The keymap\'s name') @cli.argument('-km', '--keymap', arg_only=True, required=True, help='The keymap\'s name')
@cli.argument('filename', arg_only=True, help='keymap.c file') @cli.argument('filename', arg_only=True, help='keymap.c file')
@cli.subcommand('Creates a keymap.json from a keymap.c file.') @cli.subcommand('Creates a keymap.json from a keymap.c file.')

View File

@ -7,10 +7,11 @@ from milc import cli
import qmk.path import qmk.path
from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.decorators import automagic_keyboard, automagic_keymap
from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
from qmk.keyboard import keyboard_folder
@cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), help='The configurator export to compile') @cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), help='The configurator export to compile')
@cli.argument('-kb', '--keyboard', help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.') @cli.argument('-kb', '--keyboard', type=keyboard_folder, 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('-km', '--keymap', help='The keymap to build a firmware for. Ignored when a configurator export is supplied.')
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.") @cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.") @cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.")

View File

@ -9,6 +9,7 @@ from milc import cli
import qmk.path import qmk.path
from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.decorators import automagic_keyboard, automagic_keymap
from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
from qmk.keyboard import keyboard_folder
def print_bootloader_help(): def print_bootloader_help():
@ -33,7 +34,7 @@ def print_bootloader_help():
@cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.') @cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.')
@cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.') @cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.')
@cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.') @cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
@cli.argument('-kb', '--keyboard', help='The keyboard to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.') @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='The keyboard to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.") @cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.") @cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.")
@cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.") @cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.")

View File

@ -9,6 +9,7 @@ from milc import cli
from qmk.datetime import current_datetime from qmk.datetime import current_datetime
from qmk.info import info_json from qmk.info import info_json
from qmk.info_json_encoder import InfoJSONEncoder from qmk.info_json_encoder import InfoJSONEncoder
from qmk.json_schema import json_load
from qmk.keyboard import list_keyboards from qmk.keyboard import list_keyboards
@ -18,43 +19,58 @@ def generate_api(cli):
""" """
api_data_dir = Path('api_data') api_data_dir = Path('api_data')
v1_dir = api_data_dir / 'v1' v1_dir = api_data_dir / 'v1'
keyboard_list = v1_dir / 'keyboard_list.json' keyboard_all_file = v1_dir / 'keyboards.json' # A massive JSON containing everything
keyboard_all = v1_dir / 'keyboards.json' keyboard_list_file = v1_dir / 'keyboard_list.json' # A simple list of keyboard targets
usb_file = v1_dir / 'usb.json' keyboard_aliases_file = v1_dir / 'keyboard_aliases.json' # A list of historical keyboard names and their new name
keyboard_metadata_file = v1_dir / 'keyboard_metadata.json' # All the data configurator/via needs for initialization
usb_file = v1_dir / 'usb.json' # A mapping of USB VID/PID -> keyboard target
if not api_data_dir.exists(): if not api_data_dir.exists():
api_data_dir.mkdir() api_data_dir.mkdir()
kb_all = {'last_updated': current_datetime(), 'keyboards': {}} kb_all = {}
usb_list = {'last_updated': current_datetime(), 'devices': {}} usb_list = {}
# Generate and write keyboard specific JSON files # Generate and write keyboard specific JSON files
for keyboard_name in list_keyboards(): for keyboard_name in list_keyboards():
kb_all['keyboards'][keyboard_name] = info_json(keyboard_name) kb_all[keyboard_name] = info_json(keyboard_name)
keyboard_dir = v1_dir / 'keyboards' / keyboard_name keyboard_dir = v1_dir / 'keyboards' / keyboard_name
keyboard_info = keyboard_dir / 'info.json' keyboard_info = keyboard_dir / 'info.json'
keyboard_readme = keyboard_dir / 'readme.md' keyboard_readme = keyboard_dir / 'readme.md'
keyboard_readme_src = Path('keyboards') / keyboard_name / 'readme.md' keyboard_readme_src = Path('keyboards') / keyboard_name / 'readme.md'
keyboard_dir.mkdir(parents=True, exist_ok=True) keyboard_dir.mkdir(parents=True, exist_ok=True)
keyboard_info.write_text(json.dumps({'last_updated': current_datetime(), 'keyboards': {keyboard_name: kb_all['keyboards'][keyboard_name]}})) keyboard_info.write_text(json.dumps({'last_updated': current_datetime(), 'keyboards': {keyboard_name: kb_all[keyboard_name]}}))
if keyboard_readme_src.exists(): if keyboard_readme_src.exists():
copyfile(keyboard_readme_src, keyboard_readme) copyfile(keyboard_readme_src, keyboard_readme)
if 'usb' in kb_all['keyboards'][keyboard_name]: if 'usb' in kb_all[keyboard_name]:
usb = kb_all['keyboards'][keyboard_name]['usb'] usb = kb_all[keyboard_name]['usb']
if 'vid' in usb and usb['vid'] not in usb_list['devices']: if 'vid' in usb and usb['vid'] not in usb_list:
usb_list['devices'][usb['vid']] = {} usb_list[usb['vid']] = {}
if 'pid' in usb and usb['pid'] not in usb_list['devices'][usb['vid']]: if 'pid' in usb and usb['pid'] not in usb_list[usb['vid']]:
usb_list['devices'][usb['vid']][usb['pid']] = {} usb_list[usb['vid']][usb['pid']] = {}
if 'vid' in usb and 'pid' in usb: if 'vid' in usb and 'pid' in usb:
usb_list['devices'][usb['vid']][usb['pid']][keyboard_name] = usb usb_list[usb['vid']][usb['pid']][keyboard_name] = usb
# Write the global JSON files # Write the global JSON files
keyboard_list.write_text(json.dumps({'last_updated': current_datetime(), 'keyboards': sorted(kb_all['keyboards'])}, cls=InfoJSONEncoder)) keyboard_all_file.write_text(json.dumps({'last_updated': current_datetime(), 'keyboards': kb_all}, cls=InfoJSONEncoder))
keyboard_all.write_text(json.dumps(kb_all, cls=InfoJSONEncoder)) usb_file.write_text(json.dumps({'last_updated': current_datetime(), 'usb': usb_list}, cls=InfoJSONEncoder))
usb_file.write_text(json.dumps(usb_list, cls=InfoJSONEncoder))
keyboard_list = sorted(kb_all)
keyboard_list_file.write_text(json.dumps({'last_updated': current_datetime(), 'keyboards': keyboard_list}, cls=InfoJSONEncoder))
keyboard_aliases = json_load(Path('data/mappings/keyboard_aliases.json'))
keyboard_aliases_file.write_text(json.dumps({'last_updated': current_datetime(), 'keyboard_aliases': keyboard_aliases}, cls=InfoJSONEncoder))
keyboard_metadata = {
'last_updated': current_datetime(),
'keyboards': keyboard_list,
'keyboard_aliases': keyboard_aliases,
'usb': usb_list
}
keyboard_metadata_file.write_text(json.dumps(keyboard_metadata, cls=InfoJSONEncoder))

View File

@ -6,7 +6,9 @@ from dotty_dict import dotty
from milc import cli from milc import cli
from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.decorators import automagic_keyboard, automagic_keymap
from qmk.info import _json_load, info_json from qmk.info import info_json
from qmk.json_schema import json_load
from qmk.keyboard import keyboard_folder
from qmk.path import is_keyboard, normpath from qmk.path import is_keyboard, normpath
@ -73,7 +75,7 @@ def matrix_pins(matrix_pins):
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') @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('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
@cli.argument('-kb', '--keyboard', help='Keyboard to generate config.h for.') @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to generate config.h for.')
@cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True) @cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True)
@automagic_keyboard @automagic_keyboard
@automagic_keymap @automagic_keymap
@ -92,7 +94,7 @@ def generate_config_h(cli):
# Build the info_config.h file. # Build the info_config.h file.
kb_info_json = dotty(info_json(cli.config.generate_config_h.keyboard)) kb_info_json = dotty(info_json(cli.config.generate_config_h.keyboard))
info_config_map = _json_load(Path('data/mappings/info_config.json')) info_config_map = json_load(Path('data/mappings/info_config.json'))
config_h_lines = ['/* This file was generated by `qmk generate-config-h`. Do not edit or copy.' ' */', '', '#pragma once'] config_h_lines = ['/* This file was generated by `qmk generate-config-h`. Do not edit or copy.' ' */', '', '#pragma once']

View File

@ -8,8 +8,10 @@ from jsonschema import Draft7Validator, validators
from milc import cli from milc import cli
from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.decorators import automagic_keyboard, automagic_keymap
from qmk.info import info_json, _jsonschema from qmk.info import info_json
from qmk.info_json_encoder import InfoJSONEncoder from qmk.info_json_encoder import InfoJSONEncoder
from qmk.json_schema import load_jsonschema
from qmk.keyboard import keyboard_folder
from qmk.path import is_keyboard from qmk.path import is_keyboard
@ -33,13 +35,13 @@ def strip_info_json(kb_info_json):
"""Remove the API-only properties from the info.json. """Remove the API-only properties from the info.json.
""" """
pruning_draft_7_validator = pruning_validator(Draft7Validator) pruning_draft_7_validator = pruning_validator(Draft7Validator)
schema = _jsonschema('keyboard') schema = load_jsonschema('keyboard')
validator = pruning_draft_7_validator(schema).validate validator = pruning_draft_7_validator(schema).validate
return validator(kb_info_json) return validator(kb_info_json)
@cli.argument('-kb', '--keyboard', help='Keyboard to show info for.') @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to show info for.')
@cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.') @cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.')
@cli.subcommand('Generate an info.json file for a keyboard.', hidden=False if cli.config.user.developer else True) @cli.subcommand('Generate an info.json file for a keyboard.', hidden=False if cli.config.user.developer else True)
@automagic_keyboard @automagic_keyboard

View File

@ -5,6 +5,7 @@ from milc import cli
from qmk.constants import COL_LETTERS, ROW_LETTERS from qmk.constants import COL_LETTERS, ROW_LETTERS
from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.decorators import automagic_keyboard, automagic_keymap
from qmk.info import info_json from qmk.info import info_json
from qmk.keyboard import keyboard_folder
from qmk.path import is_keyboard, normpath from qmk.path import is_keyboard, normpath
usb_properties = { usb_properties = {
@ -16,7 +17,7 @@ usb_properties = {
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') @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('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
@cli.argument('-kb', '--keyboard', help='Keyboard to generate config.h for.') @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to generate config.h for.')
@cli.subcommand('Used by the make system to generate layouts.h from info.json', hidden=True) @cli.subcommand('Used by the make system to generate layouts.h from info.json', hidden=True)
@automagic_keyboard @automagic_keyboard
@automagic_keymap @automagic_keymap

View File

@ -6,7 +6,9 @@ from dotty_dict import dotty
from milc import cli from milc import cli
from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.decorators import automagic_keyboard, automagic_keymap
from qmk.info import _json_load, info_json from qmk.info import info_json
from qmk.json_schema import json_load
from qmk.keyboard import keyboard_folder
from qmk.path import is_keyboard, normpath from qmk.path import is_keyboard, normpath
@ -37,7 +39,7 @@ def process_mapping_rule(kb_info_json, rules_key, info_dict):
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') @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('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
@cli.argument('-e', '--escape', arg_only=True, action='store_true', help="Escape spaces in quiet mode") @cli.argument('-e', '--escape', arg_only=True, action='store_true', help="Escape spaces in quiet mode")
@cli.argument('-kb', '--keyboard', help='Keyboard to generate config.h for.') @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to generate config.h for.')
@cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True) @cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True)
@automagic_keyboard @automagic_keyboard
@automagic_keymap @automagic_keymap
@ -54,7 +56,7 @@ def generate_rules_mk(cli):
return False return False
kb_info_json = dotty(info_json(cli.config.generate_rules_mk.keyboard)) kb_info_json = dotty(info_json(cli.config.generate_rules_mk.keyboard))
info_rules_map = _json_load(Path('data/mappings/info_rules.json')) info_rules_map = json_load(Path('data/mappings/info_rules.json'))
rules_mk_lines = ['# This file was generated by `qmk generate-rules-mk`. Do not edit or copy.', ''] rules_mk_lines = ['# This file was generated by `qmk generate-rules-mk`. Do not edit or copy.', '']
# Iterate through the info_rules map to generate basic rules # Iterate through the info_rules map to generate basic rules

View File

@ -10,7 +10,7 @@ from milc import cli
from qmk.info_json_encoder import InfoJSONEncoder from qmk.info_json_encoder import InfoJSONEncoder
from qmk.constants import COL_LETTERS, ROW_LETTERS from qmk.constants import COL_LETTERS, ROW_LETTERS
from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.decorators import automagic_keyboard, automagic_keymap
from qmk.keyboard import render_layouts, render_layout from qmk.keyboard import keyboard_folder, render_layouts, render_layout
from qmk.keymap import locate_keymap from qmk.keymap import locate_keymap
from qmk.info import info_json from qmk.info import info_json
from qmk.path import is_keyboard from qmk.path import is_keyboard
@ -124,7 +124,7 @@ def print_text_output(kb_info_json):
show_keymap(kb_info_json, False) show_keymap(kb_info_json, False)
@cli.argument('-kb', '--keyboard', help='Keyboard to show info for.') @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to show info for.')
@cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.') @cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.')
@cli.argument('-l', '--layouts', action='store_true', help='Render the layouts.') @cli.argument('-l', '--layouts', action='store_true', help='Render the layouts.')
@cli.argument('-m', '--matrix', action='store_true', help='Render the layouts with matrix information.') @cli.argument('-m', '--matrix', action='store_true', help='Render the layouts with matrix information.')

View File

@ -4,18 +4,14 @@ from milc import cli
import qmk.keymap import qmk.keymap
from qmk.decorators import automagic_keyboard from qmk.decorators import automagic_keyboard
from qmk.path import is_keyboard from qmk.keyboard import keyboard_folder
@cli.argument("-kb", "--keyboard", help="Specify keyboard name. Example: 1upkeyboards/1up60hse") @cli.argument("-kb", "--keyboard", type=keyboard_folder, help="Specify keyboard name. Example: 1upkeyboards/1up60hse")
@cli.subcommand("List the keymaps for a specific keyboard") @cli.subcommand("List the keymaps for a specific keyboard")
@automagic_keyboard @automagic_keyboard
def list_keymaps(cli): def list_keymaps(cli):
"""List the keymaps for a specific keyboard """List the keymaps for a specific keyboard
""" """
if not is_keyboard(cli.config.list_keymaps.keyboard):
cli.log.error('Keyboard %s does not exist!', cli.config.list_keymaps.keyboard)
return False
for name in qmk.keymap.list_keymaps(cli.config.list_keymaps.keyboard): for name in qmk.keymap.list_keymaps(cli.config.list_keymaps.keyboard):
print(name) print(name)

View File

@ -5,10 +5,11 @@ from pathlib import Path
import qmk.path import qmk.path
from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.decorators import automagic_keyboard, automagic_keymap
from qmk.keyboard import keyboard_folder
from milc import cli from milc import cli
@cli.argument('-kb', '--keyboard', help='Specify keyboard name. Example: 1upkeyboards/1up60hse') @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Specify keyboard name. Example: 1upkeyboards/1up60hse')
@cli.argument('-km', '--keymap', help='Specify the name for the new keymap directory') @cli.argument('-km', '--keymap', help='Specify the name for the new keymap directory')
@cli.subcommand('Creates a new keymap for the keyboard of your choosing') @cli.subcommand('Creates a new keymap for the keyboard of your choosing')
@automagic_keyboard @automagic_keyboard

View File

@ -13,6 +13,7 @@ from milc import cli
import qmk.keymap import qmk.keymap
from qmk.constants import KEYBOARD_OUTPUT_PREFIX from qmk.constants import KEYBOARD_OUTPUT_PREFIX
from qmk.json_schema import json_load
time_fmt = '%Y-%m-%d-%H:%M:%S' time_fmt = '%Y-%m-%d-%H:%M:%S'
@ -190,6 +191,15 @@ def parse_configurator_json(configurator_file):
""" """
# FIXME(skullydazed/anyone): Add validation here # FIXME(skullydazed/anyone): Add validation here
user_keymap = json.load(configurator_file) user_keymap = json.load(configurator_file)
orig_keyboard = user_keymap['keyboard']
aliases = json_load(Path('data/mappings/keyboard_aliases.json'))
if orig_keyboard in aliases:
if 'target' in aliases[orig_keyboard]:
user_keymap['keyboard'] = aliases[orig_keyboard]['target']
if 'layouts' in aliases[orig_keyboard] and user_keymap['layout'] in aliases[orig_keyboard]['layouts']:
user_keymap['layout'] = aliases[orig_keyboard]['layouts'][user_keymap['layout']]
return user_keymap return user_keymap

View File

@ -1,17 +1,15 @@
"""Functions that help us generate and use info.json files. """Functions that help us generate and use info.json files.
""" """
import json
from collections.abc import Mapping
from glob import glob from glob import glob
from pathlib import Path from pathlib import Path
import hjson
import jsonschema import jsonschema
from dotty_dict import dotty from dotty_dict import dotty
from milc import cli from milc import cli
from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS
from qmk.c_parse import find_layouts from qmk.c_parse import find_layouts
from qmk.json_schema import deep_update, json_load, keyboard_validate, keyboard_api_validate
from qmk.keyboard import config_h, rules_mk from qmk.keyboard import config_h, rules_mk
from qmk.keymap import list_keymaps from qmk.keymap import list_keymaps
from qmk.makefile import parse_rules_mk_file from qmk.makefile import parse_rules_mk_file
@ -82,52 +80,6 @@ def info_json(keyboard):
return info_data return info_data
def _json_load(json_file):
"""Load a json file from disk.
Note: file must be a Path object.
"""
try:
return hjson.load(json_file.open(encoding='utf-8'))
except json.decoder.JSONDecodeError as e:
cli.log.error('Invalid JSON encountered attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e)
exit(1)
def _jsonschema(schema_name):
"""Read a jsonschema file from disk.
FIXME(skullydazed/anyone): Refactor to make this a public function.
"""
schema_path = Path(f'data/schemas/{schema_name}.jsonschema')
if not schema_path.exists():
schema_path = Path('data/schemas/false.jsonschema')
return _json_load(schema_path)
def keyboard_validate(data):
"""Validates data against the keyboard jsonschema.
"""
schema = _jsonschema('keyboard')
validator = jsonschema.Draft7Validator(schema).validate
return validator(data)
def keyboard_api_validate(data):
"""Validates data against the api_keyboard jsonschema.
"""
base = _jsonschema('keyboard')
relative = _jsonschema('api_keyboard')
resolver = jsonschema.RefResolver.from_schema(base)
validator = jsonschema.Draft7Validator(relative, resolver=resolver).validate
return validator(data)
def _extract_features(info_data, rules): def _extract_features(info_data, rules):
"""Find all the features enabled in rules.mk. """Find all the features enabled in rules.mk.
""" """
@ -258,7 +210,7 @@ def _extract_config_h(info_data):
# Pull in data from the json map # Pull in data from the json map
dotty_info = dotty(info_data) dotty_info = dotty(info_data)
info_config_map = _json_load(Path('data/mappings/info_config.json')) info_config_map = json_load(Path('data/mappings/info_config.json'))
for config_key, info_dict in info_config_map.items(): for config_key, info_dict in info_config_map.items():
info_key = info_dict['info_key'] info_key = info_dict['info_key']
@ -326,7 +278,7 @@ def _extract_rules_mk(info_data):
# Pull in data from the json map # Pull in data from the json map
dotty_info = dotty(info_data) dotty_info = dotty(info_data)
info_rules_map = _json_load(Path('data/mappings/info_rules.json')) info_rules_map = json_load(Path('data/mappings/info_rules.json'))
for rules_key, info_dict in info_rules_map.items(): for rules_key, info_dict in info_rules_map.items():
info_key = info_dict['info_key'] info_key = info_dict['info_key']
@ -516,25 +468,12 @@ def unknown_processor_rules(info_data, rules):
return info_data return info_data
def deep_update(origdict, newdict):
"""Update a dictionary in place, recursing to do a deep copy.
"""
for key, value in newdict.items():
if isinstance(value, Mapping):
origdict[key] = deep_update(origdict.get(key, {}), value)
else:
origdict[key] = value
return origdict
def merge_info_jsons(keyboard, info_data): def merge_info_jsons(keyboard, info_data):
"""Return a merged copy of all the info.json files for a keyboard. """Return a merged copy of all the info.json files for a keyboard.
""" """
for info_file in find_info_json(keyboard): for info_file in find_info_json(keyboard):
# Load and validate the JSON data # Load and validate the JSON data
new_info_data = _json_load(info_file) new_info_data = json_load(info_file)
if not isinstance(new_info_data, dict): if not isinstance(new_info_data, dict):
_log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),)) _log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),))

View File

@ -0,0 +1,68 @@
"""Functions that help us generate and use info.json files.
"""
import json
from collections.abc import Mapping
from pathlib import Path
import hjson
import jsonschema
from milc import cli
def json_load(json_file):
"""Load a json file from disk.
Note: file must be a Path object.
"""
try:
return hjson.load(json_file.open())
except json.decoder.JSONDecodeError as e:
cli.log.error('Invalid JSON encountered attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e)
exit(1)
def load_jsonschema(schema_name):
"""Read a jsonschema file from disk.
FIXME(skullydazed/anyone): Refactor to make this a public function.
"""
schema_path = Path(f'data/schemas/{schema_name}.jsonschema')
if not schema_path.exists():
schema_path = Path('data/schemas/false.jsonschema')
return json_load(schema_path)
def keyboard_validate(data):
"""Validates data against the keyboard jsonschema.
"""
schema = load_jsonschema('keyboard')
validator = jsonschema.Draft7Validator(schema).validate
return validator(data)
def keyboard_api_validate(data):
"""Validates data against the api_keyboard jsonschema.
"""
base = load_jsonschema('keyboard')
relative = load_jsonschema('api_keyboard')
resolver = jsonschema.RefResolver.from_schema(base)
validator = jsonschema.Draft7Validator(relative, resolver=resolver).validate
return validator(data)
def deep_update(origdict, newdict):
"""Update a dictionary in place, recursing to do a deep copy.
"""
for key, value in newdict.items():
if isinstance(value, Mapping):
origdict[key] = deep_update(origdict.get(key, {}), value)
else:
origdict[key] = value
return origdict

View File

@ -7,7 +7,9 @@ import os
from glob import glob from glob import glob
from qmk.c_parse import parse_config_h_file from qmk.c_parse import parse_config_h_file
from qmk.json_schema import json_load
from qmk.makefile import parse_rules_mk_file from qmk.makefile import parse_rules_mk_file
from qmk.path import is_keyboard
BOX_DRAWING_CHARACTERS = { BOX_DRAWING_CHARACTERS = {
"unicode": { "unicode": {
@ -31,6 +33,28 @@ BOX_DRAWING_CHARACTERS = {
base_path = os.path.join(os.getcwd(), "keyboards") + os.path.sep base_path = os.path.join(os.getcwd(), "keyboards") + os.path.sep
def keyboard_folder(keyboard):
"""Returns the actual keyboard folder.
This checks aliases and DEFAULT_FOLDER to resolve the actual path for a keyboard.
"""
aliases = json_load(Path('data/mappings/keyboard_aliases.json'))
if keyboard in aliases:
keyboard = aliases[keyboard].get('target', keyboard)
rules_mk_file = Path(base_path, keyboard, 'rules.mk')
if rules_mk_file.exists():
rules_mk = parse_rules_mk_file(rules_mk_file)
keyboard = rules_mk.get('DEFAULT_FOLDER', keyboard)
if not is_keyboard(keyboard):
raise ValueError(f'Invalid keyboard: {keyboard}')
return keyboard
def _find_name(path): def _find_name(path):
"""Determine the keyboard name by stripping off the base_path and rules.mk. """Determine the keyboard name by stripping off the base_path and rules.mk.
""" """

View File

@ -15,6 +15,7 @@ def is_keyboard(keyboard_name):
if keyboard_name: if keyboard_name:
keyboard_path = QMK_FIRMWARE / 'keyboards' / keyboard_name keyboard_path = QMK_FIRMWARE / 'keyboards' / keyboard_name
rules_mk = keyboard_path / 'rules.mk' rules_mk = keyboard_path / 'rules.mk'
return rules_mk.exists() return rules_mk.exists()

View File

@ -134,8 +134,8 @@ def test_list_keymaps_vendor_kb_rev():
def test_list_keymaps_no_keyboard_found(): def test_list_keymaps_no_keyboard_found():
result = check_subcommand('list-keymaps', '-kb', 'asdfghjkl') result = check_subcommand('list-keymaps', '-kb', 'asdfghjkl')
check_returncode(result, [1]) check_returncode(result, [2])
assert 'does not exist' in result.stdout assert 'invalid keyboard_folder value' in result.stdout
def test_json2c(): def test_json2c():