Merge remote-tracking branch 'upstream/develop' into xap
This commit is contained in:
commit
575d8c19fc
1132 changed files with 38265 additions and 8171 deletions
|
@ -1,7 +1,7 @@
|
|||
"""This script automates the generation of the QMK API data.
|
||||
"""
|
||||
from pathlib import Path
|
||||
from shutil import copyfile
|
||||
import shutil
|
||||
import json
|
||||
|
||||
from milc import cli
|
||||
|
@ -12,28 +12,42 @@ from qmk.json_encoders import InfoJSONEncoder
|
|||
from qmk.json_schema import json_load
|
||||
from qmk.keyboard import find_readme, list_keyboards
|
||||
|
||||
TEMPLATE_PATH = Path('data/templates/api/')
|
||||
BUILD_API_PATH = Path('.build/api_data/')
|
||||
|
||||
|
||||
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't write the data to disk.")
|
||||
@cli.argument('-f', '--filter', arg_only=True, action='append', default=[], help="Filter the list of keyboards based on partial name matches the supplied value. May be passed multiple times.")
|
||||
@cli.subcommand('Creates a new keymap for the keyboard of your choosing', hidden=False if cli.config.user.developer else True)
|
||||
def generate_api(cli):
|
||||
"""Generates the QMK API data.
|
||||
"""
|
||||
api_data_dir = Path('api_data')
|
||||
v1_dir = api_data_dir / 'v1'
|
||||
if BUILD_API_PATH.exists():
|
||||
shutil.rmtree(BUILD_API_PATH)
|
||||
|
||||
shutil.copytree(TEMPLATE_PATH, BUILD_API_PATH)
|
||||
|
||||
v1_dir = BUILD_API_PATH / 'v1'
|
||||
keyboard_all_file = v1_dir / 'keyboards.json' # A massive JSON containing everything
|
||||
keyboard_list_file = v1_dir / 'keyboard_list.json' # A simple list of keyboard targets
|
||||
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():
|
||||
api_data_dir.mkdir()
|
||||
# Filter down when required
|
||||
keyboard_list = list_keyboards()
|
||||
if cli.args.filter:
|
||||
kb_list = []
|
||||
for keyboard_name in keyboard_list:
|
||||
if any(i in keyboard_name for i in cli.args.filter):
|
||||
kb_list.append(keyboard_name)
|
||||
keyboard_list = kb_list
|
||||
|
||||
kb_all = {}
|
||||
usb_list = {}
|
||||
|
||||
# Generate and write keyboard specific JSON files
|
||||
for keyboard_name in list_keyboards():
|
||||
for keyboard_name in keyboard_list:
|
||||
kb_all[keyboard_name] = info_json(keyboard_name)
|
||||
keyboard_dir = v1_dir / 'keyboards' / keyboard_name
|
||||
keyboard_info = keyboard_dir / 'info.json'
|
||||
|
@ -47,7 +61,7 @@ def generate_api(cli):
|
|||
cli.log.debug('Wrote file %s', keyboard_info)
|
||||
|
||||
if keyboard_readme_src:
|
||||
copyfile(keyboard_readme_src, keyboard_readme)
|
||||
shutil.copyfile(keyboard_readme_src, keyboard_readme)
|
||||
cli.log.debug('Copied %s -> %s', keyboard_readme_src, keyboard_readme)
|
||||
|
||||
if 'usb' in kb_all[keyboard_name]:
|
||||
|
|
|
@ -21,18 +21,7 @@ def direct_pins(direct_pins, postfix):
|
|||
cols = ','.join(map(str, [col or 'NO_PIN' for col in row]))
|
||||
rows.append('{' + cols + '}')
|
||||
|
||||
col_count = len(direct_pins[0])
|
||||
row_count = len(direct_pins)
|
||||
|
||||
return f"""
|
||||
#ifndef MATRIX_COLS{postfix}
|
||||
# define MATRIX_COLS{postfix} {col_count}
|
||||
#endif // MATRIX_COLS{postfix}
|
||||
|
||||
#ifndef MATRIX_ROWS{postfix}
|
||||
# define MATRIX_ROWS{postfix} {row_count}
|
||||
#endif // MATRIX_ROWS{postfix}
|
||||
|
||||
#ifndef DIRECT_PINS{postfix}
|
||||
# define DIRECT_PINS{postfix} {{ {", ".join(rows)} }}
|
||||
#endif // DIRECT_PINS{postfix}
|
||||
|
@ -42,14 +31,9 @@ def direct_pins(direct_pins, postfix):
|
|||
def pin_array(define, pins, postfix):
|
||||
"""Return the config.h lines that set a pin array.
|
||||
"""
|
||||
pin_num = len(pins)
|
||||
pin_array = ', '.join(map(str, [pin or 'NO_PIN' for pin in pins]))
|
||||
|
||||
return f"""
|
||||
#ifndef {define}S{postfix}
|
||||
# define {define}S{postfix} {pin_num}
|
||||
#endif // {define}S{postfix}
|
||||
|
||||
#ifndef {define}_PINS{postfix}
|
||||
# define {define}_PINS{postfix} {{ {pin_array} }}
|
||||
#endif // {define}_PINS{postfix}
|
||||
|
@ -73,6 +57,24 @@ def matrix_pins(matrix_pins, postfix=''):
|
|||
return '\n'.join(pins)
|
||||
|
||||
|
||||
def generate_matrix_size(kb_info_json, config_h_lines):
|
||||
"""Add the matrix size to the config.h.
|
||||
"""
|
||||
if 'matrix_pins' in kb_info_json:
|
||||
col_count = kb_info_json['matrix_size']['cols']
|
||||
row_count = kb_info_json['matrix_size']['rows']
|
||||
|
||||
config_h_lines.append(f"""
|
||||
#ifndef MATRIX_COLS
|
||||
# define MATRIX_COLS {col_count}
|
||||
#endif // MATRIX_COLS
|
||||
|
||||
#ifndef MATRIX_ROWS
|
||||
# define MATRIX_ROWS {row_count}
|
||||
#endif // MATRIX_ROWS
|
||||
""")
|
||||
|
||||
|
||||
def generate_config_items(kb_info_json, config_h_lines):
|
||||
"""Iterate through the info_config map to generate basic config values.
|
||||
"""
|
||||
|
@ -80,7 +82,7 @@ def generate_config_items(kb_info_json, config_h_lines):
|
|||
|
||||
for config_key, info_dict in info_config_map.items():
|
||||
info_key = info_dict['info_key']
|
||||
key_type = info_dict.get('value_type', 'str')
|
||||
key_type = info_dict.get('value_type', 'raw')
|
||||
to_config = info_dict.get('to_config', True)
|
||||
|
||||
if not to_config:
|
||||
|
@ -108,6 +110,11 @@ def generate_config_items(kb_info_json, config_h_lines):
|
|||
config_h_lines.append(f'#ifndef {key}')
|
||||
config_h_lines.append(f'# define {key} {value}')
|
||||
config_h_lines.append(f'#endif // {key}')
|
||||
elif key_type == 'str':
|
||||
config_h_lines.append('')
|
||||
config_h_lines.append(f'#ifndef {config_key}')
|
||||
config_h_lines.append(f'# define {config_key} "{config_value}"')
|
||||
config_h_lines.append(f'#endif // {config_key}')
|
||||
elif key_type == 'bcd_version':
|
||||
(major, minor, revision) = config_value.split('.')
|
||||
config_h_lines.append('')
|
||||
|
@ -183,6 +190,8 @@ def generate_config_h(cli):
|
|||
|
||||
generate_config_items(kb_info_json, config_h_lines)
|
||||
|
||||
generate_matrix_size(kb_info_json, config_h_lines)
|
||||
|
||||
if 'matrix_pins' in kb_info_json:
|
||||
config_h_lines.append(matrix_pins(kb_info_json['matrix_pins']))
|
||||
|
||||
|
@ -196,7 +205,7 @@ def generate_config_h(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(config_h)
|
||||
cli.args.output.write_text(config_h, encoding='utf-8')
|
||||
|
||||
if not cli.args.quiet:
|
||||
cli.log.info('Wrote info_config.h to %s.', cli.args.output)
|
||||
|
|
|
@ -18,7 +18,8 @@ ignored_titles = ["Format code according to conventions"]
|
|||
def _is_ignored(title):
|
||||
for ignore in ignored_titles:
|
||||
if ignore in title:
|
||||
return
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _get_pr_info(cache, gh, pr_num):
|
||||
|
|
|
@ -7,7 +7,10 @@ from subprocess import DEVNULL
|
|||
from milc import cli
|
||||
|
||||
DOCS_PATH = Path('docs/')
|
||||
BUILD_PATH = Path('.build/docs/')
|
||||
BUILD_PATH = Path('.build/')
|
||||
BUILD_DOCS_PATH = BUILD_PATH / 'docs'
|
||||
DOXYGEN_PATH = BUILD_PATH / 'doxygen'
|
||||
MOXYGEN_PATH = BUILD_DOCS_PATH / 'internals'
|
||||
|
||||
|
||||
@cli.subcommand('Build QMK documentation.', hidden=False if cli.config.user.developer else True)
|
||||
|
@ -18,10 +21,12 @@ def generate_docs(cli):
|
|||
* [ ] Add a real build step... something static docs
|
||||
"""
|
||||
|
||||
if BUILD_PATH.exists():
|
||||
shutil.rmtree(BUILD_PATH)
|
||||
if BUILD_DOCS_PATH.exists():
|
||||
shutil.rmtree(BUILD_DOCS_PATH)
|
||||
if DOXYGEN_PATH.exists():
|
||||
shutil.rmtree(DOXYGEN_PATH)
|
||||
|
||||
shutil.copytree(DOCS_PATH, BUILD_PATH)
|
||||
shutil.copytree(DOCS_PATH, BUILD_DOCS_PATH)
|
||||
|
||||
# When not verbose we want to hide all output
|
||||
args = {
|
||||
|
@ -30,10 +35,10 @@ def generate_docs(cli):
|
|||
'stdin': DEVNULL,
|
||||
}
|
||||
|
||||
cli.log.info('Generating internal docs...')
|
||||
cli.log.info('Generating docs...')
|
||||
|
||||
# Generate internal docs
|
||||
cli.run(['doxygen', 'Doxyfile'], **args)
|
||||
cli.run(['moxygen', '-q', '-a', '-g', '-o', BUILD_PATH / 'internals_%s.md', 'doxygen/xml'], **args)
|
||||
cli.run(['moxygen', '-q', '-g', '-o', MOXYGEN_PATH / '%s.md', DOXYGEN_PATH / 'xml'], **args)
|
||||
|
||||
cli.log.info('Successfully generated internal docs to %s.', BUILD_PATH)
|
||||
cli.log.info('Successfully generated docs to %s.', BUILD_DOCS_PATH)
|
||||
|
|
|
@ -40,16 +40,12 @@ def generate_layouts(cli):
|
|||
# Build the layouts.h file.
|
||||
layouts_h_lines = ['/* This file was generated by `qmk generate-layouts`. Do not edit or copy.', ' */', '', '#pragma once']
|
||||
|
||||
if 'matrix_pins' in kb_info_json:
|
||||
if 'direct' in kb_info_json['matrix_pins']:
|
||||
col_num = len(kb_info_json['matrix_pins']['direct'][0])
|
||||
row_num = len(kb_info_json['matrix_pins']['direct'])
|
||||
elif 'cols' in kb_info_json['matrix_pins'] and 'rows' in kb_info_json['matrix_pins']:
|
||||
col_num = len(kb_info_json['matrix_pins']['cols'])
|
||||
row_num = len(kb_info_json['matrix_pins']['rows'])
|
||||
else:
|
||||
cli.log.error('%s: Invalid matrix config.', cli.config.generate_layouts.keyboard)
|
||||
return False
|
||||
if 'matrix_size' not in kb_info_json:
|
||||
cli.log.error('%s: Invalid matrix config.', cli.config.generate_layouts.keyboard)
|
||||
return False
|
||||
|
||||
col_num = kb_info_json['matrix_size']['cols']
|
||||
row_num = kb_info_json['matrix_size']['rows']
|
||||
|
||||
for layout_name in kb_info_json['layouts']:
|
||||
if kb_info_json['layouts'][layout_name]['c_macro']:
|
||||
|
|
|
@ -19,7 +19,7 @@ def process_mapping_rule(kb_info_json, rules_key, info_dict):
|
|||
return None
|
||||
|
||||
info_key = info_dict['info_key']
|
||||
key_type = info_dict.get('value_type', 'str')
|
||||
key_type = info_dict.get('value_type', 'raw')
|
||||
|
||||
try:
|
||||
rules_value = kb_info_json[info_key]
|
||||
|
@ -29,9 +29,11 @@ def process_mapping_rule(kb_info_json, rules_key, info_dict):
|
|||
if key_type in ['array', 'list']:
|
||||
return f'{rules_key} ?= {" ".join(rules_value)}'
|
||||
elif key_type == 'bool':
|
||||
return f'{rules_key} ?= {"on" if rules_value else "off"}'
|
||||
return f'{rules_key} ?= {"yes" if rules_value else "no"}'
|
||||
elif key_type == 'mapping':
|
||||
return '\n'.join([f'{key} ?= {value}' for key, value in rules_value.items()])
|
||||
elif key_type == 'str':
|
||||
return f'{rules_key} ?= "{rules_value}"'
|
||||
|
||||
return f'{rules_key} ?= {rules_value}'
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
"""Generate a keymap.c from a configurator export.
|
||||
"""
|
||||
import json
|
||||
|
||||
from argcomplete.completers import FilesCompleter
|
||||
from milc import cli
|
||||
|
||||
import qmk.keymap
|
||||
import qmk.path
|
||||
from qmk.commands import parse_configurator_json
|
||||
|
||||
|
||||
@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
|
||||
|
@ -19,14 +18,8 @@ def json2c(cli):
|
|||
This command uses the `qmk.keymap` module to generate a keymap.c from a configurator export. The generated keymap is written to stdout, or to a file if -o is provided.
|
||||
"""
|
||||
|
||||
try:
|
||||
# Parse the configurator from json file (or stdin)
|
||||
user_keymap = json.load(cli.args.filename)
|
||||
|
||||
except json.decoder.JSONDecodeError as ex:
|
||||
cli.log.error('The JSON input does not appear to be valid.')
|
||||
cli.log.error(ex)
|
||||
return False
|
||||
# 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 == '-':
|
||||
|
|
|
@ -15,48 +15,11 @@ from qmk.json_schema import load_jsonschema
|
|||
from qmk.path import keyboard
|
||||
from qmk.json_encoders import InfoJSONEncoder
|
||||
from qmk.json_schema import deep_update
|
||||
from qmk.constants import MCU2BOOTLOADER
|
||||
|
||||
COMMUNITY = Path('layouts/default/')
|
||||
TEMPLATE = Path('data/templates/keyboard/')
|
||||
|
||||
MCU2BOOTLOADER = {
|
||||
"MKL26Z64": "halfkay",
|
||||
"MK20DX128": "halfkay",
|
||||
"MK20DX256": "halfkay",
|
||||
"MK66FX1M0": "halfkay",
|
||||
"STM32F042": "stm32-dfu",
|
||||
"STM32F072": "stm32-dfu",
|
||||
"STM32F103": "stm32duino",
|
||||
"STM32F303": "stm32-dfu",
|
||||
"STM32F401": "stm32-dfu",
|
||||
"STM32F405": "stm32-dfu",
|
||||
"STM32F407": "stm32-dfu",
|
||||
"STM32F411": "stm32-dfu",
|
||||
"STM32F446": "stm32-dfu",
|
||||
"STM32G431": "stm32-dfu",
|
||||
"STM32G474": "stm32-dfu",
|
||||
"STM32L412": "stm32-dfu",
|
||||
"STM32L422": "stm32-dfu",
|
||||
"STM32L432": "stm32-dfu",
|
||||
"STM32L433": "stm32-dfu",
|
||||
"STM32L442": "stm32-dfu",
|
||||
"STM32L443": "stm32-dfu",
|
||||
"GD32VF103": "gd32v-dfu",
|
||||
"WB32F3G71": "wb32-dfu",
|
||||
"atmega16u2": "atmel-dfu",
|
||||
"atmega32u2": "atmel-dfu",
|
||||
"atmega16u4": "atmel-dfu",
|
||||
"atmega32u4": "atmel-dfu",
|
||||
"at90usb162": "atmel-dfu",
|
||||
"at90usb646": "atmel-dfu",
|
||||
"at90usb647": "atmel-dfu",
|
||||
"at90usb1286": "atmel-dfu",
|
||||
"at90usb1287": "atmel-dfu",
|
||||
"atmega32a": "bootloadhid",
|
||||
"atmega328p": "usbasploader",
|
||||
"atmega328": "usbasploader",
|
||||
}
|
||||
|
||||
# defaults
|
||||
schema = dotty(load_jsonschema('keyboard'))
|
||||
mcu_types = sorted(schema["properties.processor.enum"], key=str.casefold)
|
||||
|
@ -141,20 +104,42 @@ def augment_community_info(src, dest):
|
|||
dest.write_text(json.dumps(info, cls=InfoJSONEncoder))
|
||||
|
||||
|
||||
def _question(*args, **kwargs):
|
||||
"""Ugly workaround until 'milc' learns to display a repromt msg
|
||||
"""
|
||||
# TODO: Remove this once milc.questions.question handles reprompt messages
|
||||
|
||||
reprompt = kwargs["reprompt"]
|
||||
del kwargs["reprompt"]
|
||||
validate = kwargs["validate"]
|
||||
del kwargs["validate"]
|
||||
|
||||
prompt = args[0]
|
||||
ret = None
|
||||
while not ret:
|
||||
ret = question(prompt, **kwargs)
|
||||
if not validate(ret):
|
||||
ret = None
|
||||
prompt = reprompt
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def prompt_keyboard():
|
||||
prompt = """{fg_yellow}Name Your Keyboard Project{style_reset_all}
|
||||
|
||||
For more infomation, see:
|
||||
https://docs.qmk.fm/#/hardware_keyboard_guidelines?id=naming-your-keyboardproject
|
||||
|
||||
keyboard Name? """
|
||||
Keyboard Name? """
|
||||
|
||||
return question(prompt, validate=lambda x: not keyboard(x).exists())
|
||||
errmsg = 'Keyboard already exists! Please choose a different name:'
|
||||
|
||||
return _question(prompt, reprompt=errmsg, validate=lambda x: not keyboard(x).exists())
|
||||
|
||||
|
||||
def prompt_user():
|
||||
prompt = """{fg_yellow}Attribution{style_reset_all}
|
||||
|
||||
prompt = """
|
||||
{fg_yellow}Attribution{style_reset_all}
|
||||
Used for maintainer, copyright, etc
|
||||
|
||||
Your GitHub Username? """
|
||||
|
@ -162,8 +147,8 @@ Your GitHub Username? """
|
|||
|
||||
|
||||
def prompt_name(def_name):
|
||||
prompt = """{fg_yellow}More Attribution{style_reset_all}
|
||||
|
||||
prompt = """
|
||||
{fg_yellow}More Attribution{style_reset_all}
|
||||
Used for maintainer, copyright, etc
|
||||
|
||||
Your Real Name? """
|
||||
|
@ -171,8 +156,8 @@ Your Real Name? """
|
|||
|
||||
|
||||
def prompt_layout():
|
||||
prompt = """{fg_yellow}Pick Base Layout{style_reset_all}
|
||||
|
||||
prompt = """
|
||||
{fg_yellow}Pick Base Layout{style_reset_all}
|
||||
As a starting point, one of the common layouts can be used to bootstrap the process
|
||||
|
||||
Default Layout? """
|
||||
|
@ -184,8 +169,8 @@ Default Layout? """
|
|||
|
||||
|
||||
def prompt_mcu():
|
||||
prompt = """{fg_yellow}What Powers Your Project{style_reset_all}
|
||||
|
||||
prompt = """
|
||||
{fg_yellow}What Powers Your Project{style_reset_all}
|
||||
For more infomation, see:
|
||||
https://docs.qmk.fm/#/compatible_microcontrollers
|
||||
|
||||
|
@ -199,7 +184,7 @@ MCU? """
|
|||
@cli.argument('-kb', '--keyboard', help='Specify the name for the new keyboard directory', arg_only=True, type=keyboard_name)
|
||||
@cli.argument('-l', '--layout', help='Community layout to bootstrap with', arg_only=True, type=layout_type)
|
||||
@cli.argument('-t', '--type', help='Specify the keyboard MCU type', arg_only=True, type=mcu_type)
|
||||
@cli.argument('-u', '--username', help='Specify your username (default from Git config)', arg_only=True)
|
||||
@cli.argument('-u', '--username', help='Specify your username (default from Git config)', dest='name')
|
||||
@cli.argument('-n', '--realname', help='Specify your real name if you want to use that. Defaults to username', arg_only=True)
|
||||
@cli.subcommand('Creates a new keyboard directory')
|
||||
def new_keyboard(cli):
|
||||
|
@ -209,8 +194,8 @@ def new_keyboard(cli):
|
|||
cli.echo('')
|
||||
|
||||
kb_name = cli.args.keyboard if cli.args.keyboard else prompt_keyboard()
|
||||
user_name = cli.args.username if cli.args.username else prompt_user()
|
||||
real_name = cli.args.realname or cli.args.username if cli.args.realname or cli.args.username else prompt_name(user_name)
|
||||
user_name = cli.config.new_keyboard.name if cli.config.new_keyboard.name else prompt_user()
|
||||
real_name = cli.args.realname or cli.config.new_keyboard.name if cli.args.realname or cli.config.new_keyboard.name else prompt_name(user_name)
|
||||
default_layout = cli.args.layout if cli.args.layout else prompt_layout()
|
||||
mcu = cli.args.type if cli.args.type else prompt_mcu()
|
||||
bootloader = select_default_bootloader(mcu)
|
||||
|
@ -223,7 +208,15 @@ def new_keyboard(cli):
|
|||
cli.log.error(f'Keyboard {{fg_cyan}}{kb_name}{{fg_reset}} already exists! Please choose a different name.')
|
||||
return 1
|
||||
|
||||
tokens = {'YEAR': str(date.today().year), 'KEYBOARD': kb_name, 'USER_NAME': user_name, 'REAL_NAME': real_name, 'LAYOUT': default_layout, 'MCU': mcu, 'BOOTLOADER': bootloader}
|
||||
tokens = { # Comment here is to force multiline formatting
|
||||
'YEAR': str(date.today().year),
|
||||
'KEYBOARD': kb_name,
|
||||
'USER_NAME': user_name,
|
||||
'REAL_NAME': real_name,
|
||||
'LAYOUT': default_layout,
|
||||
'MCU': mcu,
|
||||
'BOOTLOADER': bootloader
|
||||
}
|
||||
|
||||
if cli.config.general.verbose:
|
||||
cli.log.info("Creating keyboard with:")
|
||||
|
|
|
@ -12,7 +12,7 @@ from milc import cli
|
|||
def pytest(cli):
|
||||
"""Run several linting/testing commands.
|
||||
"""
|
||||
nose2 = cli.run(['nose2', '-v', '-t' 'lib/python', *cli.args.test], capture_output=False, stdin=DEVNULL)
|
||||
nose2 = cli.run(['nose2', '-v', '-t', 'lib/python', *cli.args.test], capture_output=False, stdin=DEVNULL)
|
||||
flake8 = cli.run(['flake8', 'lib/python'], capture_output=False, stdin=DEVNULL)
|
||||
|
||||
return flake8.returncode | nose2.returncode
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue