diff options
Diffstat (limited to 'lib/python')
| -rwxr-xr-x | lib/python/qmk/cli/json2c.py | 13 | ||||
| -rw-r--r-- | lib/python/qmk/commands.py | 19 | ||||
| -rw-r--r-- | lib/python/qmk/json_schema.py | 8 | ||||
| -rw-r--r-- | lib/python/qmk/path.py | 6 | ||||
| -rw-r--r-- | lib/python/qmk/tests/test_cli_commands.py | 12 |
5 files changed, 41 insertions, 17 deletions
diff --git a/lib/python/qmk/cli/json2c.py b/lib/python/qmk/cli/json2c.py index ae8248e6b7..2873a9bfd3 100755 --- a/lib/python/qmk/cli/json2c.py +++ b/lib/python/qmk/cli/json2c.py | |||
| @@ -1,12 +1,11 @@ | |||
| 1 | """Generate a keymap.c from a configurator export. | 1 | """Generate a keymap.c from a configurator export. |
| 2 | """ | 2 | """ |
| 3 | import json | ||
| 4 | |||
| 5 | from argcomplete.completers import FilesCompleter | 3 | from argcomplete.completers import FilesCompleter |
| 6 | from milc import cli | 4 | from milc import cli |
| 7 | 5 | ||
| 8 | import qmk.keymap | 6 | import qmk.keymap |
| 9 | import qmk.path | 7 | import qmk.path |
| 8 | from qmk.commands import parse_configurator_json | ||
| 10 | 9 | ||
| 11 | 10 | ||
| 12 | @cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') | 11 | @cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') |
| @@ -19,14 +18,8 @@ def json2c(cli): | |||
| 19 | 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. | 18 | 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. |
| 20 | """ | 19 | """ |
| 21 | 20 | ||
| 22 | try: | 21 | # Parse the configurator from json file (or stdin) |
| 23 | # Parse the configurator from json file (or stdin) | 22 | user_keymap = parse_configurator_json(cli.args.filename) |
| 24 | user_keymap = json.load(cli.args.filename) | ||
| 25 | |||
| 26 | except json.decoder.JSONDecodeError as ex: | ||
| 27 | cli.log.error('The JSON input does not appear to be valid.') | ||
| 28 | cli.log.error(ex) | ||
| 29 | return False | ||
| 30 | 23 | ||
| 31 | # Environment processing | 24 | # Environment processing |
| 32 | if cli.args.output and cli.args.output.name == '-': | 25 | if cli.args.output and cli.args.output.name == '-': |
diff --git a/lib/python/qmk/commands.py b/lib/python/qmk/commands.py index 275cd72e5c..e38f17156a 100644 --- a/lib/python/qmk/commands.py +++ b/lib/python/qmk/commands.py | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | """Helper functions for commands. | 1 | """Helper functions for commands. |
| 2 | """ | 2 | """ |
| 3 | import json | ||
| 4 | import os | 3 | import os |
| 5 | import sys | 4 | import sys |
| 6 | import shutil | 5 | import shutil |
| @@ -9,10 +8,11 @@ from subprocess import DEVNULL | |||
| 9 | from time import strftime | 8 | from time import strftime |
| 10 | 9 | ||
| 11 | from milc import cli | 10 | from milc import cli |
| 11 | import jsonschema | ||
| 12 | 12 | ||
| 13 | import qmk.keymap | 13 | import qmk.keymap |
| 14 | from qmk.constants import QMK_FIRMWARE, KEYBOARD_OUTPUT_PREFIX | 14 | from qmk.constants import QMK_FIRMWARE, KEYBOARD_OUTPUT_PREFIX |
| 15 | from qmk.json_schema import json_load | 15 | from qmk.json_schema import json_load, validate |
| 16 | 16 | ||
| 17 | time_fmt = '%Y-%m-%d-%H:%M:%S' | 17 | time_fmt = '%Y-%m-%d-%H:%M:%S' |
| 18 | 18 | ||
| @@ -185,6 +185,10 @@ def compile_configurator_json(user_keymap, bootloader=None, parallel=1, **env_va | |||
| 185 | 185 | ||
| 186 | A command to run to compile and flash the C file. | 186 | A command to run to compile and flash the C file. |
| 187 | """ | 187 | """ |
| 188 | # In case the user passes a keymap.json from a keymap directory directly to the CLI. | ||
| 189 | # e.g.: qmk compile - < keyboards/clueboard/california/keymaps/default/keymap.json | ||
| 190 | user_keymap["keymap"] = user_keymap.get("keymap", "default_json") | ||
| 191 | |||
| 188 | # Write the keymap.c file | 192 | # Write the keymap.c file |
| 189 | keyboard_filesafe = user_keymap['keyboard'].replace('/', '_') | 193 | keyboard_filesafe = user_keymap['keyboard'].replace('/', '_') |
| 190 | target = f'{keyboard_filesafe}_{user_keymap["keymap"]}' | 194 | target = f'{keyboard_filesafe}_{user_keymap["keymap"]}' |
| @@ -248,8 +252,15 @@ def compile_configurator_json(user_keymap, bootloader=None, parallel=1, **env_va | |||
| 248 | def parse_configurator_json(configurator_file): | 252 | def parse_configurator_json(configurator_file): |
| 249 | """Open and parse a configurator json export | 253 | """Open and parse a configurator json export |
| 250 | """ | 254 | """ |
| 251 | # FIXME(skullydazed/anyone): Add validation here | 255 | user_keymap = json_load(configurator_file) |
| 252 | user_keymap = json.load(configurator_file) | 256 | # Validate against the jsonschema |
| 257 | try: | ||
| 258 | validate(user_keymap, 'qmk.keymap.v1') | ||
| 259 | |||
| 260 | except jsonschema.ValidationError as e: | ||
| 261 | cli.log.error(f'Invalid JSON keymap: {configurator_file} : {e.message}') | ||
| 262 | exit(1) | ||
| 263 | |||
| 253 | orig_keyboard = user_keymap['keyboard'] | 264 | orig_keyboard = user_keymap['keyboard'] |
| 254 | aliases = json_load(Path('data/mappings/keyboard_aliases.json')) | 265 | aliases = json_load(Path('data/mappings/keyboard_aliases.json')) |
| 255 | 266 | ||
diff --git a/lib/python/qmk/json_schema.py b/lib/python/qmk/json_schema.py index ffc7c6bcd1..2b48782fbb 100644 --- a/lib/python/qmk/json_schema.py +++ b/lib/python/qmk/json_schema.py | |||
| @@ -16,7 +16,11 @@ def json_load(json_file): | |||
| 16 | Note: file must be a Path object. | 16 | Note: file must be a Path object. |
| 17 | """ | 17 | """ |
| 18 | try: | 18 | try: |
| 19 | return hjson.load(json_file.open(encoding='utf-8')) | 19 | # Get the IO Stream for Path objects |
| 20 | # Not necessary if the data is provided via stdin | ||
| 21 | if isinstance(json_file, Path): | ||
| 22 | json_file = json_file.open(encoding='utf-8') | ||
| 23 | return hjson.load(json_file) | ||
| 20 | 24 | ||
| 21 | except (json.decoder.JSONDecodeError, hjson.HjsonDecodeError) as e: | 25 | except (json.decoder.JSONDecodeError, hjson.HjsonDecodeError) as e: |
| 22 | cli.log.error('Invalid JSON encountered attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e) | 26 | cli.log.error('Invalid JSON encountered attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e) |
| @@ -62,7 +66,7 @@ def create_validator(schema): | |||
| 62 | """Creates a validator for the given schema id. | 66 | """Creates a validator for the given schema id. |
| 63 | """ | 67 | """ |
| 64 | schema_store = compile_schema_store() | 68 | schema_store = compile_schema_store() |
| 65 | resolver = jsonschema.RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store) | 69 | resolver = jsonschema.RefResolver.from_schema(schema_store[schema], store=schema_store) |
| 66 | 70 | ||
| 67 | return jsonschema.Draft7Validator(schema_store[schema], resolver=resolver).validate | 71 | return jsonschema.Draft7Validator(schema_store[schema], resolver=resolver).validate |
| 68 | 72 | ||
diff --git a/lib/python/qmk/path.py b/lib/python/qmk/path.py index dfb8371f84..9b94abbc12 100644 --- a/lib/python/qmk/path.py +++ b/lib/python/qmk/path.py | |||
| @@ -70,9 +70,13 @@ def normpath(path): | |||
| 70 | 70 | ||
| 71 | 71 | ||
| 72 | class FileType(argparse.FileType): | 72 | class FileType(argparse.FileType): |
| 73 | def __init__(self, encoding='UTF-8'): | ||
| 74 | # Use UTF8 by default for stdin | ||
| 75 | return super().__init__(encoding=encoding) | ||
| 76 | |||
| 73 | def __call__(self, string): | 77 | def __call__(self, string): |
| 74 | """normalize and check exists | 78 | """normalize and check exists |
| 75 | otherwise magic strings like '-' for stdin resolve to bad paths | 79 | otherwise magic strings like '-' for stdin resolve to bad paths |
| 76 | """ | 80 | """ |
| 77 | norm = normpath(string) | 81 | norm = normpath(string) |
| 78 | return super().__call__(norm if norm.exists() else string) | 82 | return norm if norm.exists() else super().__call__(string) |
diff --git a/lib/python/qmk/tests/test_cli_commands.py b/lib/python/qmk/tests/test_cli_commands.py index c379c92229..d5cf1841c9 100644 --- a/lib/python/qmk/tests/test_cli_commands.py +++ b/lib/python/qmk/tests/test_cli_commands.py | |||
| @@ -156,6 +156,18 @@ def test_json2c_stdin(): | |||
| 156 | assert result.stdout == '#include QMK_KEYBOARD_H\nconst uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {\t[0] = LAYOUT_ortho_1x1(KC_A)};\n\n' | 156 | assert result.stdout == '#include QMK_KEYBOARD_H\nconst uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {\t[0] = LAYOUT_ortho_1x1(KC_A)};\n\n' |
| 157 | 157 | ||
| 158 | 158 | ||
| 159 | def test_json2c_wrong_json(): | ||
| 160 | result = check_subcommand('json2c', 'keyboards/handwired/pytest/info.json') | ||
| 161 | check_returncode(result, [1]) | ||
| 162 | assert 'Invalid JSON keymap' in result.stdout | ||
| 163 | |||
| 164 | |||
| 165 | def test_json2c_no_json(): | ||
| 166 | result = check_subcommand('json2c', 'keyboards/handwired/pytest/pytest.h') | ||
| 167 | check_returncode(result, [1]) | ||
| 168 | assert 'Invalid JSON encountered' in result.stdout | ||
| 169 | |||
| 170 | |||
| 159 | def test_info(): | 171 | def test_info(): |
| 160 | result = check_subcommand('info', '-kb', 'handwired/pytest/basic') | 172 | result = check_subcommand('info', '-kb', 'handwired/pytest/basic') |
| 161 | check_returncode(result) | 173 | check_returncode(result) |
