summaryrefslogtreecommitdiff
path: root/lib/python
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python')
-rwxr-xr-xlib/python/qmk/cli/json2c.py13
-rw-r--r--lib/python/qmk/commands.py19
-rw-r--r--lib/python/qmk/json_schema.py8
-rw-r--r--lib/python/qmk/path.py6
-rw-r--r--lib/python/qmk/tests/test_cli_commands.py12
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"""
3import json
4
5from argcomplete.completers import FilesCompleter 3from argcomplete.completers import FilesCompleter
6from milc import cli 4from milc import cli
7 5
8import qmk.keymap 6import qmk.keymap
9import qmk.path 7import qmk.path
8from 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"""
3import json
4import os 3import os
5import sys 4import sys
6import shutil 5import shutil
@@ -9,10 +8,11 @@ from subprocess import DEVNULL
9from time import strftime 8from time import strftime
10 9
11from milc import cli 10from milc import cli
11import jsonschema
12 12
13import qmk.keymap 13import qmk.keymap
14from qmk.constants import QMK_FIRMWARE, KEYBOARD_OUTPUT_PREFIX 14from qmk.constants import QMK_FIRMWARE, KEYBOARD_OUTPUT_PREFIX
15from qmk.json_schema import json_load 15from qmk.json_schema import json_load, validate
16 16
17time_fmt = '%Y-%m-%d-%H:%M:%S' 17time_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
248def parse_configurator_json(configurator_file): 252def 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
72class FileType(argparse.FileType): 72class 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
159def 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
165def 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
159def test_info(): 171def 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)