diff options
Diffstat (limited to 'lib')
m--------- | lib/chibios | 0 | ||||
m--------- | lib/chibios-contrib | 0 | ||||
-rwxr-xr-x | lib/python/qmk/cli/doctor/__init__.py | 5 | ||||
-rw-r--r-- | lib/python/qmk/cli/doctor/check.py (renamed from lib/python/qmk/os_helpers/__init__.py) | 18 | ||||
-rw-r--r-- | lib/python/qmk/cli/doctor/linux.py (renamed from lib/python/qmk/os_helpers/linux/__init__.py) | 26 | ||||
-rw-r--r-- | lib/python/qmk/cli/doctor/macos.py | 13 | ||||
-rwxr-xr-x | lib/python/qmk/cli/doctor/main.py (renamed from lib/python/qmk/cli/doctor.py) | 43 | ||||
-rw-r--r-- | lib/python/qmk/cli/doctor/windows.py | 14 | ||||
-rwxr-xr-x | lib/python/qmk/cli/format/json.py | 5 | ||||
-rw-r--r-- | lib/python/qmk/info.py | 11 | ||||
-rw-r--r-- | lib/python/qmk/json_schema.py | 34 |
11 files changed, 96 insertions, 73 deletions
diff --git a/lib/chibios b/lib/chibios -Subproject ffe54d63cb10a355add318f8e922e39f1c3d4bf +Subproject 413e39c5681d181720440f2a8b7391f581788d7 diff --git a/lib/chibios-contrib b/lib/chibios-contrib -Subproject 61baa6b036138c155f7cfc5646d833d9423f324 +Subproject 9c2bfa6aeba993345f5425d82807c101f8e25e6 diff --git a/lib/python/qmk/cli/doctor/__init__.py b/lib/python/qmk/cli/doctor/__init__.py new file mode 100755 index 0000000000..272e042023 --- /dev/null +++ b/lib/python/qmk/cli/doctor/__init__.py @@ -0,0 +1,5 @@ +"""QMK Doctor + +Check out the user's QMK environment and make sure it's ready to compile. +""" +from .main import doctor diff --git a/lib/python/qmk/os_helpers/__init__.py b/lib/python/qmk/cli/doctor/check.py index 3e98db3c32..a0bbb28168 100644 --- a/lib/python/qmk/os_helpers/__init__.py +++ b/lib/python/qmk/cli/doctor/check.py @@ -1,4 +1,4 @@ -"""OS-agnostic helper functions +"""Check for specific programs. """ from enum import Enum import re @@ -30,7 +30,7 @@ ESSENTIAL_BINARIES = { } -def parse_gcc_version(version): +def _parse_gcc_version(version): m = re.match(r"(\d+)(?:\.(\d+))?(?:\.(\d+))?", version) return { @@ -40,7 +40,7 @@ def parse_gcc_version(version): } -def check_arm_gcc_version(): +def _check_arm_gcc_version(): """Returns True if the arm-none-eabi-gcc version is not known to cause problems. """ if 'output' in ESSENTIAL_BINARIES['arm-none-eabi-gcc']: @@ -50,7 +50,7 @@ def check_arm_gcc_version(): return CheckStatus.OK # Right now all known arm versions are ok -def check_avr_gcc_version(): +def _check_avr_gcc_version(): """Returns True if the avr-gcc version is not known to cause problems. """ rc = CheckStatus.ERROR @@ -60,7 +60,7 @@ def check_avr_gcc_version(): cli.log.info('Found avr-gcc version %s', version_number) rc = CheckStatus.OK - parsed_version = parse_gcc_version(version_number) + parsed_version = _parse_gcc_version(version_number) if parsed_version['major'] > 8: cli.log.warning('{fg_yellow}We do not recommend avr-gcc newer than 8. Downgrading to 8.x is recommended.') rc = CheckStatus.WARNING @@ -68,7 +68,7 @@ def check_avr_gcc_version(): return rc -def check_avrdude_version(): +def _check_avrdude_version(): if 'output' in ESSENTIAL_BINARIES['avrdude']: last_line = ESSENTIAL_BINARIES['avrdude']['output'].split('\n')[-2] version_number = last_line.split()[2][:-1] @@ -77,7 +77,7 @@ def check_avrdude_version(): return CheckStatus.OK -def check_dfu_util_version(): +def _check_dfu_util_version(): if 'output' in ESSENTIAL_BINARIES['dfu-util']: first_line = ESSENTIAL_BINARIES['dfu-util']['output'].split('\n')[0] version_number = first_line.split()[1] @@ -86,7 +86,7 @@ def check_dfu_util_version(): return CheckStatus.OK -def check_dfu_programmer_version(): +def _check_dfu_programmer_version(): if 'output' in ESSENTIAL_BINARIES['dfu-programmer']: first_line = ESSENTIAL_BINARIES['dfu-programmer']['output'].split('\n')[0] version_number = first_line.split()[1] @@ -111,7 +111,7 @@ def check_binary_versions(): """Check the versions of ESSENTIAL_BINARIES """ versions = [] - for check in (check_arm_gcc_version, check_avr_gcc_version, check_avrdude_version, check_dfu_util_version, check_dfu_programmer_version): + for check in (_check_arm_gcc_version, _check_avr_gcc_version, _check_avrdude_version, _check_dfu_util_version, _check_dfu_programmer_version): versions.append(check()) return versions diff --git a/lib/python/qmk/os_helpers/linux/__init__.py b/lib/python/qmk/cli/doctor/linux.py index 008654ab0f..c0b77216a1 100644 --- a/lib/python/qmk/os_helpers/linux/__init__.py +++ b/lib/python/qmk/cli/doctor/linux.py @@ -1,11 +1,13 @@ """OS-specific functions for: Linux """ -from pathlib import Path +import platform import shutil +from pathlib import Path from milc import cli + from qmk.constants import QMK_FIRMWARE -from qmk.os_helpers import CheckStatus +from .check import CheckStatus def _udev_rule(vid, pid=None, *args): @@ -138,3 +140,23 @@ def check_modem_manager(): """(TODO): Add check for non-systemd systems """ return False + + +def os_test_linux(): + """Run the Linux specific tests. + """ + # Don't bother with udev on WSL, for now + if 'microsoft' in platform.uname().release.lower(): + cli.log.info("Detected {fg_cyan}Linux (WSL){fg_reset}.") + + # https://github.com/microsoft/WSL/issues/4197 + if QMK_FIRMWARE.as_posix().startswith("/mnt"): + cli.log.warning("I/O performance on /mnt may be extremely slow.") + return CheckStatus.WARNING + + return CheckStatus.OK + else: + cli.log.info("Detected {fg_cyan}Linux{fg_reset}.") + from .linux import check_udev_rules + + return check_udev_rules() diff --git a/lib/python/qmk/cli/doctor/macos.py b/lib/python/qmk/cli/doctor/macos.py new file mode 100644 index 0000000000..00fb272858 --- /dev/null +++ b/lib/python/qmk/cli/doctor/macos.py @@ -0,0 +1,13 @@ +import platform + +from milc import cli + +from .check import CheckStatus + + +def os_test_macos(): + """Run the Mac specific tests. + """ + cli.log.info("Detected {fg_cyan}macOS %s{fg_reset}.", platform.mac_ver()[0]) + + return CheckStatus.OK diff --git a/lib/python/qmk/cli/doctor.py b/lib/python/qmk/cli/doctor/main.py index 9e10570620..45b0203b6e 100755 --- a/lib/python/qmk/cli/doctor.py +++ b/lib/python/qmk/cli/doctor/main.py @@ -7,9 +7,10 @@ from subprocess import DEVNULL from milc import cli from milc.questions import yesno + from qmk import submodules from qmk.constants import QMK_FIRMWARE -from qmk.os_helpers import CheckStatus, check_binaries, check_binary_versions, check_submodules, check_git_repo +from .check import CheckStatus, check_binaries, check_binary_versions, check_submodules, check_git_repo def os_tests(): @@ -18,53 +19,19 @@ def os_tests(): platform_id = platform.platform().lower() if 'darwin' in platform_id or 'macos' in platform_id: + from .macos import os_test_macos return os_test_macos() elif 'linux' in platform_id: + from .linux import os_test_linux return os_test_linux() elif 'windows' in platform_id: + from .windows import os_test_windows return os_test_windows() else: cli.log.warning('Unsupported OS detected: %s', platform_id) return CheckStatus.WARNING -def os_test_linux(): - """Run the Linux specific tests. - """ - # Don't bother with udev on WSL, for now - if 'microsoft' in platform.uname().release.lower(): - cli.log.info("Detected {fg_cyan}Linux (WSL){fg_reset}.") - - # https://github.com/microsoft/WSL/issues/4197 - if QMK_FIRMWARE.as_posix().startswith("/mnt"): - cli.log.warning("I/O performance on /mnt may be extremely slow.") - return CheckStatus.WARNING - - return CheckStatus.OK - else: - cli.log.info("Detected {fg_cyan}Linux{fg_reset}.") - from qmk.os_helpers.linux import check_udev_rules - - return check_udev_rules() - - -def os_test_macos(): - """Run the Mac specific tests. - """ - cli.log.info("Detected {fg_cyan}macOS %s{fg_reset}.", platform.mac_ver()[0]) - - return CheckStatus.OK - - -def os_test_windows(): - """Run the Windows specific tests. - """ - win32_ver = platform.win32_ver() - cli.log.info("Detected {fg_cyan}Windows %s (%s){fg_reset}.", win32_ver[0], win32_ver[1]) - - return CheckStatus.OK - - @cli.argument('-y', '--yes', action='store_true', arg_only=True, help='Answer yes to all questions.') @cli.argument('-n', '--no', action='store_true', arg_only=True, help='Answer no to all questions.') @cli.subcommand('Basic QMK environment checks') diff --git a/lib/python/qmk/cli/doctor/windows.py b/lib/python/qmk/cli/doctor/windows.py new file mode 100644 index 0000000000..381ab36fde --- /dev/null +++ b/lib/python/qmk/cli/doctor/windows.py @@ -0,0 +1,14 @@ +import platform + +from milc import cli + +from .check import CheckStatus + + +def os_test_windows(): + """Run the Windows specific tests. + """ + win32_ver = platform.win32_ver() + cli.log.info("Detected {fg_cyan}Windows %s (%s){fg_reset}.", win32_ver[0], win32_ver[1]) + + return CheckStatus.OK diff --git a/lib/python/qmk/cli/format/json.py b/lib/python/qmk/cli/format/json.py index 1358c70e7a..19d504491f 100755 --- a/lib/python/qmk/cli/format/json.py +++ b/lib/python/qmk/cli/format/json.py @@ -8,7 +8,7 @@ from jsonschema import ValidationError from milc import cli from qmk.info import info_json -from qmk.json_schema import json_load, keyboard_validate +from qmk.json_schema import json_load, validate from qmk.json_encoders import InfoJSONEncoder, KeymapJSONEncoder from qmk.path import normpath @@ -23,14 +23,13 @@ def format_json(cli): if cli.args.format == 'auto': try: - keyboard_validate(json_file) + validate(json_file, 'qmk.keyboard.v1') json_encoder = InfoJSONEncoder except ValidationError as e: cli.log.warning('File %s did not validate as a keyboard:\n\t%s', cli.args.json_file, e) cli.log.info('Treating %s as a keymap file.', cli.args.json_file) json_encoder = KeymapJSONEncoder - elif cli.args.format == 'keyboard': json_encoder = InfoJSONEncoder elif cli.args.format == 'keymap': diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py index 47c8bff7a8..5525f0fe6b 100644 --- a/lib/python/qmk/info.py +++ b/lib/python/qmk/info.py @@ -9,7 +9,7 @@ from milc import cli from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS from qmk.c_parse import find_layouts -from qmk.json_schema import deep_update, json_load, keyboard_validate, keyboard_api_validate +from qmk.json_schema import deep_update, json_load, validate from qmk.keyboard import config_h, rules_mk from qmk.keymap import list_keymaps from qmk.makefile import parse_rules_mk_file @@ -66,7 +66,7 @@ def info_json(keyboard): # Validate against the jsonschema try: - keyboard_api_validate(info_data) + validate(info_data, 'qmk.api.keyboard.v1') except jsonschema.ValidationError as e: json_path = '.'.join([str(p) for p in e.absolute_path]) @@ -143,10 +143,7 @@ def _pin_name(pin): elif pin == 'NO_PIN': return None - elif pin[0] in 'ABCDEFGHIJK' and pin[1].isdigit(): - return pin - - raise ValueError(f'Invalid pin: {pin}') + return pin def _extract_pins(pins): @@ -493,7 +490,7 @@ def merge_info_jsons(keyboard, info_data): continue try: - keyboard_validate(new_info_data) + validate(new_info_data, 'qmk.keyboard.v1') except jsonschema.ValidationError as e: json_path = '.'.join([str(p) for p in e.absolute_path]) cli.log.error('Not including data from file: %s', info_file) diff --git a/lib/python/qmk/json_schema.py b/lib/python/qmk/json_schema.py index 077dfcaa93..3e5663a291 100644 --- a/lib/python/qmk/json_schema.py +++ b/lib/python/qmk/json_schema.py @@ -24,9 +24,10 @@ def json_load(json_file): def load_jsonschema(schema_name): """Read a jsonschema file from disk. - - FIXME(skullydazed/anyone): Refactor to make this a public function. """ + if Path(schema_name).exists(): + return json_load(schema_name) + schema_path = Path(f'data/schemas/{schema_name}.jsonschema') if not schema_path.exists(): @@ -35,28 +36,33 @@ def load_jsonschema(schema_name): return json_load(schema_path) -def keyboard_validate(data): - """Validates data against the keyboard jsonschema. +def create_validator(schema): + """Creates a validator for the given schema id. """ - schema = load_jsonschema('keyboard') - validator = jsonschema.Draft7Validator(schema).validate + schema_store = {} - return validator(data) + for schema_file in Path('data/schemas').glob('*.jsonschema'): + schema_data = load_jsonschema(schema_file) + if not isinstance(schema_data, dict): + cli.log.debug('Skipping schema file %s', schema_file) + continue + schema_store[schema_data['$id']] = schema_data + + resolver = jsonschema.RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store) + + return jsonschema.Draft7Validator(schema_store[schema], resolver=resolver).validate -def keyboard_api_validate(data): - """Validates data against the api_keyboard jsonschema. +def validate(data, schema): + """Validates data against a schema. """ - base = load_jsonschema('keyboard') - relative = load_jsonschema('api_keyboard') - resolver = jsonschema.RefResolver.from_schema(base) - validator = jsonschema.Draft7Validator(relative, resolver=resolver).validate + validator = create_validator(schema) return validator(data) def deep_update(origdict, newdict): - """Update a dictionary in place, recursing to do a deep copy. + """Update a dictionary in place, recursing to do a depth-first deep copy. """ for key, value in newdict.items(): if isinstance(value, Mapping): |