diff options
author | QMK Bot <hello@qmk.fm> | 2021-03-24 16:27:28 +0000 |
---|---|---|
committer | QMK Bot <hello@qmk.fm> | 2021-03-24 16:27:28 +0000 |
commit | 0dc0516f0c38ce1eb5e7e2ec2a69b743c33e9ce6 (patch) | |
tree | d38b0682e31545e5875a7cddf4e473fd67dd0ad7 | |
parent | 743d6c430bf09710be9a1055c353fbbceed939ac (diff) | |
parent | 299008be36076343edadb7a36bf2fff820425ad1 (diff) | |
download | qmk_firmware-0dc0516f0c38ce1eb5e7e2ec2a69b743c33e9ce6.tar.gz qmk_firmware-0dc0516f0c38ce1eb5e7e2ec2a69b743c33e9ce6.zip |
Merge remote-tracking branch 'origin/master' into develop
-rw-r--r-- | data/mappings/keyboard_aliases.json | 443 | ||||
-rw-r--r-- | lib/python/qmk/cli/c2json.py | 3 | ||||
-rwxr-xr-x | lib/python/qmk/cli/compile.py | 3 | ||||
-rw-r--r-- | lib/python/qmk/cli/flash.py | 3 | ||||
-rwxr-xr-x | lib/python/qmk/cli/generate/api.py | 50 | ||||
-rwxr-xr-x | lib/python/qmk/cli/generate/config_h.py | 8 | ||||
-rwxr-xr-x | lib/python/qmk/cli/generate/info_json.py | 8 | ||||
-rwxr-xr-x | lib/python/qmk/cli/generate/layouts.py | 3 | ||||
-rwxr-xr-x | lib/python/qmk/cli/generate/rules_mk.py | 8 | ||||
-rwxr-xr-x | lib/python/qmk/cli/info.py | 4 | ||||
-rw-r--r-- | lib/python/qmk/cli/list/keymaps.py | 8 | ||||
-rwxr-xr-x | lib/python/qmk/cli/new/keymap.py | 3 | ||||
-rw-r--r-- | lib/python/qmk/commands.py | 10 | ||||
-rw-r--r-- | lib/python/qmk/info.py | 69 | ||||
-rw-r--r-- | lib/python/qmk/json_schema.py | 68 | ||||
-rw-r--r-- | lib/python/qmk/keyboard.py | 24 | ||||
-rw-r--r-- | lib/python/qmk/path.py | 1 | ||||
-rw-r--r-- | lib/python/qmk/tests/test_cli_commands.py | 4 |
18 files changed, 614 insertions, 106 deletions
diff --git a/data/mappings/keyboard_aliases.json b/data/mappings/keyboard_aliases.json new file mode 100644 index 000000000..5a2f7e3ae --- /dev/null +++ b/data/mappings/keyboard_aliases.json | |||
@@ -0,0 +1,443 @@ | |||
1 | { | ||
2 | # Format for each entry: | ||
3 | # <alias>: { | ||
4 | # target: <keyboard_folder>, | ||
5 | # layouts: { | ||
6 | # <layout_alias>: <layout_target> | ||
7 | # } | ||
8 | # } | ||
9 | # | ||
10 | # Both target and layouts are optional. | ||
11 | '2_milk': { | ||
12 | target: 'spaceman/2_milk' | ||
13 | }, | ||
14 | 'aeboards/ext65': { | ||
15 | target: 'aeboards/ext65/rev1' | ||
16 | }, | ||
17 | 'ai03/equinox': { | ||
18 | target: 'ai03/equinox/rev1' | ||
19 | }, | ||
20 | aleth42: { | ||
21 | target: 'aleth42/rev1' | ||
22 | }, | ||
23 | alice: { | ||
24 | target: 'tgr/alice' | ||
25 | }, | ||
26 | angel17: { | ||
27 | target: 'angel17/alpha' | ||
28 | }, | ||
29 | angel64: { | ||
30 | target: 'angel64/alpha' | ||
31 | }, | ||
32 | at101_blackheart: { | ||
33 | target: 'at101_bh' | ||
34 | }, | ||
35 | 'atom47/rev2': { | ||
36 | target: 'maartenwut/atom47/rev2' | ||
37 | }, | ||
38 | 'atom47/rev3': { | ||
39 | target: 'maartenwut/atom47/rev3' | ||
40 | }, | ||
41 | bear_face: { | ||
42 | target: 'bear_face/v1' | ||
43 | }, | ||
44 | 'bpiphany/pegasushoof': { | ||
45 | target: 'bpiphany/pegasushoof/2013' | ||
46 | }, | ||
47 | chavdai40: { | ||
48 | target: 'chavdai40/rev1' | ||
49 | }, | ||
50 | 'candybar/lefty': { | ||
51 | target: 'tkc/candybar/lefty' | ||
52 | }, | ||
53 | 'candybar/righty': { | ||
54 | target: 'tkc/candybar/righty' | ||
55 | }, | ||
56 | canoe: { | ||
57 | target: 'percent/canoe' | ||
58 | }, | ||
59 | 'cmm_studio/saka68': { | ||
60 | target: 'cmm_studio/saka68/solder' | ||
61 | }, | ||
62 | 'crkbd/rev1': { | ||
63 | target: 'crkbd/rev1/legacy' | ||
64 | }, | ||
65 | 'doro67/multi': { | ||
66 | layouts: { | ||
67 | LAYOUT_ansi: 'LAYOUT_65_ansi_blocker' | ||
68 | } | ||
69 | }, | ||
70 | 'doro67/regular': { | ||
71 | layouts: { | ||
72 | LAYOUT: 'LAYOUT_65_ansi_blocker' | ||
73 | } | ||
74 | }, | ||
75 | 'doro67/rgb': { | ||
76 | layouts: { | ||
77 | LAYOUT: 'LAYOUT_65_ansi_blocker' | ||
78 | } | ||
79 | }, | ||
80 | drakon: { | ||
81 | target: 'jagdpietr/drakon' | ||
82 | }, | ||
83 | 'dztech/dz60rgb': { | ||
84 | target: 'dztech/dz60rgb/v1' | ||
85 | }, | ||
86 | 'dztech/dz60rgb_ansi': { | ||
87 | target: 'dztech/dz60rgb_ansi/v1' | ||
88 | }, | ||
89 | 'dztech/dz60rgb_wkl': { | ||
90 | target: 'dztech/dz60rgb_wkl/v1' | ||
91 | }, | ||
92 | 'dztech/dz65rgb': { | ||
93 | target: 'dztech/dz65rgb/v1' | ||
94 | }, | ||
95 | eek: { | ||
96 | target: 'eek/silk_down' | ||
97 | }, | ||
98 | ergoinu: { | ||
99 | target: 'dm9records/ergoinu' | ||
100 | }, | ||
101 | 'exclusive/e85': { | ||
102 | target: 'exclusive/e85/hotswap' | ||
103 | }, | ||
104 | gh60: { | ||
105 | target: 'gh60/revc' | ||
106 | }, | ||
107 | 'handwired/ferris': { | ||
108 | target: 'ferris/0_1' | ||
109 | }, | ||
110 | 'helix/pico/sc/back': { | ||
111 | target: 'helix/pico/sc' | ||
112 | }, | ||
113 | 'helix/pico/sc/under': { | ||
114 | target: 'helix/pico/sc' | ||
115 | }, | ||
116 | 'helix/rev2/back/oled': { | ||
117 | target: 'helix/rev2/back' | ||
118 | }, | ||
119 | 'helix/rev2/oled': { | ||
120 | target: 'helix/rev2' | ||
121 | }, | ||
122 | 'helix/rev2/oled/back': { | ||
123 | target: 'helix/rev2/back' | ||
124 | }, | ||
125 | 'helix/rev2/oled/under': { | ||
126 | target: 'helix/rev2/under' | ||
127 | }, | ||
128 | 'helix/rev2/sc/back': { | ||
129 | target: 'helix/rev2/sc' | ||
130 | }, | ||
131 | 'helix/rev2/sc/oled': { | ||
132 | target: 'helix/rev2/sc' | ||
133 | }, | ||
134 | 'helix/rev2/sc/oledback': { | ||
135 | target: 'helix/rev2/sc' | ||
136 | }, | ||
137 | 'helix/rev2/sc/oledunder': { | ||
138 | target: 'helix/rev2/sc' | ||
139 | }, | ||
140 | 'helix/rev2/sc/under': { | ||
141 | target: 'helix/rev2/sc' | ||
142 | }, | ||
143 | 'helix/rev2/under': { | ||
144 | target: 'helix/rev2/sc' | ||
145 | }, | ||
146 | 'helix/rev2/under/oled': { | ||
147 | target: 'helix/rev2/under' | ||
148 | }, | ||
149 | id80: { | ||
150 | target: 'id80/ansi' | ||
151 | }, | ||
152 | idb_60: { | ||
153 | target: 'idb/idb_60', | ||
154 | layouts: { | ||
155 | LAYOUT: 'LAYOUT_all' | ||
156 | } | ||
157 | }, | ||
158 | jones: { | ||
159 | target: 'jones/v03_1' | ||
160 | }, | ||
161 | katana60: { | ||
162 | target: 'rominronin/katana60/rev1' | ||
163 | }, | ||
164 | 'kbdfans/kbd67mkiirgb': { | ||
165 | target: 'kbdfans/kbd67/mkiirgb', | ||
166 | layouts: { | ||
167 | LAYOUT: 'LAYOUT_65_ansi_blocker' | ||
168 | } | ||
169 | }, | ||
170 | 'kbdfans/kbd67/mkiirgb': { | ||
171 | target: 'kbdfans/kbd67/mkiirgb/v1' | ||
172 | }, | ||
173 | 'keebio/dsp40': { | ||
174 | target: 'keebio/dsp40/rev1' | ||
175 | }, | ||
176 | 'keycapsss/plaid_pad': { | ||
177 | target: 'keycapsss/plaid_pad/rev1' | ||
178 | }, | ||
179 | kudox: { | ||
180 | target: 'kudox/rev1' | ||
181 | }, | ||
182 | 'lfkeyboards/lfk78': { | ||
183 | target: 'lfkeyboards/lfk78/revj' | ||
184 | }, | ||
185 | 'lfkeyboards/smk65': { | ||
186 | target: 'lfkeyboards/smk65/revb' | ||
187 | }, | ||
188 | 'maartenwut/atom47/rev2': { | ||
189 | target: 'evyd13/atom47/rev2' | ||
190 | }, | ||
191 | 'maartenwut/atom47/rev3': { | ||
192 | target: 'evyd13/atom47/rev3' | ||
193 | }, | ||
194 | 'maartenwut/eon40': { | ||
195 | target: 'evyd13/eon40' | ||
196 | }, | ||
197 | 'maartenwut/eon65': { | ||
198 | target: 'evyd13/eon65' | ||
199 | }, | ||
200 | 'maartenwut/eon75': { | ||
201 | target: 'evyd13/eon75' | ||
202 | }, | ||
203 | 'maartenwut/eon87': { | ||
204 | target: 'evyd13/eon87' | ||
205 | }, | ||
206 | 'maartenwut/eon95': { | ||
207 | target: 'evyd13/eon95' | ||
208 | }, | ||
209 | 'maartenwut/gh80_1800': { | ||
210 | target: 'evyd13/gh80_1800' | ||
211 | }, | ||
212 | 'maartenwut/gh80_3700': { | ||
213 | target: 'evyd13/gh80_3700' | ||
214 | }, | ||
215 | 'maartenwut/minitomic': { | ||
216 | target: 'evyd13/minitomic' | ||
217 | }, | ||
218 | 'maartenwut/mx5160': { | ||
219 | target: 'evyd13/mx5160' | ||
220 | }, | ||
221 | 'maartenwut/nt660': { | ||
222 | target: 'evyd13/nt660' | ||
223 | }, | ||
224 | 'maartenwut/omrontkl': { | ||
225 | target: 'evyd13/omrontkl' | ||
226 | }, | ||
227 | 'maartenwut/plain60': { | ||
228 | target: 'evyd13/plain60' | ||
229 | }, | ||
230 | 'maartenwut/pockettype': { | ||
231 | target: 'evyd13/pockettype' | ||
232 | }, | ||
233 | 'maartenwut/quackfire': { | ||
234 | target: 'evyd13/quackfire' | ||
235 | }, | ||
236 | 'maartenwut/solheim68': { | ||
237 | target: 'evyd13/solheim68' | ||
238 | }, | ||
239 | 'maartenwut/ta65': { | ||
240 | target: 'evyd13/ta65' | ||
241 | }, | ||
242 | 'maartenwut/wasdat': { | ||
243 | target: 'evyd13/wasdat' | ||
244 | }, | ||
245 | 'maartenwut/wasdat_code': { | ||
246 | target: 'evyd13/wasdat_code' | ||
247 | }, | ||
248 | 'maartenwut/wonderland': { | ||
249 | target: 'evyd13/wonderland' | ||
250 | }, | ||
251 | 'mechlovin/hannah910': { | ||
252 | target: 'mechlovin/hannah910/rev1' | ||
253 | }, | ||
254 | 'mechlovin/adelais/rgb_led': { | ||
255 | target: 'mechlovin/adelais/rgb_led/rev1' | ||
256 | }, | ||
257 | 'mechlovin/adelais/standard_led': { | ||
258 | target: 'mechlovin/adelais/standard_led/rev2' | ||
259 | }, | ||
260 | 'mechlovin/delphine': { | ||
261 | target: 'mechlovin/delphine/mono_led' | ||
262 | }, | ||
263 | 'mechlovin/hannah60rgb': { | ||
264 | target: 'mechlovin/hannah60rgb/rev1' | ||
265 | }, | ||
266 | 'melgeek/z70ultra': { | ||
267 | target: 'melgeek/z70ultra/rev1' | ||
268 | }, | ||
269 | 'mechlovin/hannah65': { | ||
270 | target: 'mechlovin/hannah65/rev1' | ||
271 | }, | ||
272 | model01: { | ||
273 | target: 'keyboardio/model01' | ||
274 | }, | ||
275 | m0lly: { | ||
276 | target: 'tkc/m0lly' | ||
277 | }, | ||
278 | 'montsinger/rebound': { | ||
279 | target: 'montsinger/rebound/rev1' | ||
280 | }, | ||
281 | nomu30: { | ||
282 | target: 'nomu30/rev1' | ||
283 | }, | ||
284 | 'noxary/268_2': { | ||
285 | layouts: { | ||
286 | LAYOUT: 'LAYOUT_65_ansi_blocker' | ||
287 | } | ||
288 | }, | ||
289 | oddball: { | ||
290 | target: 'oddball/v1' | ||
291 | }, | ||
292 | omnikey_blackheart: { | ||
293 | target: 'omnikey_bh' | ||
294 | }, | ||
295 | 'pabile/p20': { | ||
296 | target: 'pabile/p20/ver1' | ||
297 | }, | ||
298 | 'pancake/feather': { | ||
299 | target: 'spaceman/pancake/feather' | ||
300 | }, | ||
301 | 'pancake/promicro': { | ||
302 | target: 'spaceman/pancake/promicro' | ||
303 | }, | ||
304 | 'percent/canoe': { | ||
305 | layouts: { | ||
306 | LAYOUT_iso: 'LAYOUT_65_iso_blocker' | ||
307 | } | ||
308 | }, | ||
309 | plaid: { | ||
310 | target: 'dm9records/plaid' | ||
311 | }, | ||
312 | plain60: { | ||
313 | target: 'maartenwut/plain60' | ||
314 | }, | ||
315 | 'ploopyco/trackball': { | ||
316 | target: 'ploopyco/trackball/rev1_005' | ||
317 | }, | ||
318 | polilla: { | ||
319 | target: 'polilla/rev1' | ||
320 | }, | ||
321 | 'preonic/rev1': { | ||
322 | layouts: { | ||
323 | LAYOUT_preonic_grid: 'LAYOUT_ortho_5x12' | ||
324 | } | ||
325 | }, | ||
326 | 'preonic/rev2': { | ||
327 | layouts: { | ||
328 | LAYOUT_preonic_grid: 'LAYOUT_ortho_5x12' | ||
329 | } | ||
330 | }, | ||
331 | 'preonic/rev3': { | ||
332 | layouts: { | ||
333 | LAYOUT_preonic_grid: 'LAYOUT_ortho_5x12' | ||
334 | } | ||
335 | }, | ||
336 | 'primekb/prime_l': { | ||
337 | target: 'primekb/prime_l/v1' | ||
338 | }, | ||
339 | 'primekb/prime_l_v2': { | ||
340 | target: 'primekb/prime_l/v2' | ||
341 | }, | ||
342 | 'projectkb/alice': { | ||
343 | target: 'projectkb/alice/rev1' | ||
344 | }, | ||
345 | 'rama/koyu': { | ||
346 | target: 'wilba_tech/rama_works_koyu' | ||
347 | }, | ||
348 | 'rama/m6_a': { | ||
349 | target: 'wilba_tech/rama_works_m6_a' | ||
350 | }, | ||
351 | 'rama/m6_b': { | ||
352 | target: 'wilba_tech/rama_works_m6_b' | ||
353 | }, | ||
354 | 'rama/m10_b': { | ||
355 | target: 'wilba_tech/rama_works_m10_b' | ||
356 | }, | ||
357 | 'rama/m60_a': { | ||
358 | target: 'wilba_tech/rama_works_m60_a' | ||
359 | }, | ||
360 | 'rama/u80_a': { | ||
361 | target: 'wilba_tech/rama_works_u80_a' | ||
362 | }, | ||
363 | 'ramonimbao/herringbone': { | ||
364 | target: 'ramonimbao/herringbone/v1' | ||
365 | }, | ||
366 | 'rgbkb/pan': { | ||
367 | target: 'rgbkb/pan/rev1/32a' | ||
368 | }, | ||
369 | 'rgbkb/pan/rev1': { | ||
370 | target: 'rgbkb/pan/rev1/32a' | ||
371 | }, | ||
372 | romac: { | ||
373 | target: 'kingly_keys/romac' | ||
374 | }, | ||
375 | ropro: { | ||
376 | target: 'kingly_keys/ropro' | ||
377 | }, | ||
378 | satan: { | ||
379 | target: 'gh60/satan' | ||
380 | }, | ||
381 | skog: { | ||
382 | target: 'percent/skog' | ||
383 | }, | ||
384 | speedo: { | ||
385 | target: 'cozykeys/speedo/v2' | ||
386 | }, | ||
387 | stoutgat: { | ||
388 | target: 'tkw/stoutgat/v1' | ||
389 | }, | ||
390 | suihankey: { | ||
391 | target: 'suihankey/split/alpha' | ||
392 | }, | ||
393 | ta65: { | ||
394 | target: 'maartenwut/ta65' | ||
395 | }, | ||
396 | tartan: { | ||
397 | target: 'dm9records/tartan' | ||
398 | }, | ||
399 | tkc1800: { | ||
400 | target: 'tkc/tkc1800' | ||
401 | }, | ||
402 | 'tkw/stoutgat/v2': { | ||
403 | target: 'tkw/stoutgat/v2/f411' | ||
404 | }, | ||
405 | underscore33: { | ||
406 | target: 'underscore33/rev1' | ||
407 | }, | ||
408 | vinta: { | ||
409 | layouts: { | ||
410 | LAYOUT_67_ansi: 'LAYOUT_65_ansi_blocker' | ||
411 | } | ||
412 | }, | ||
413 | wasdat: { | ||
414 | target: 'maartenwut/wasdat' | ||
415 | }, | ||
416 | 'westfoxtrot/cypher': { | ||
417 | target: 'westfoxtrot/cypher/rev1' | ||
418 | }, | ||
419 | 'whale/sk': { | ||
420 | target: 'whale/sk/v3' | ||
421 | }, | ||
422 | 'xelus/dawn60': { | ||
423 | target: 'xelus/dawn60/rev1' | ||
424 | }, | ||
425 | 'xelus/valor': { | ||
426 | target: 'xelus/valor/rev1' | ||
427 | }, | ||
428 | yd60mq: { | ||
429 | target: 'yd60mq/12led' | ||
430 | }, | ||
431 | ymd75: { | ||
432 | target: 'ymd75/rev1' | ||
433 | }, | ||
434 | z150_blackheart: { | ||
435 | target: 'z150_bh' | ||
436 | }, | ||
437 | zeal60: { | ||
438 | target: 'wilba_tech/zeal60' | ||
439 | }, | ||
440 | zeal65: { | ||
441 | target: 'wilba_tech/zeal65' | ||
442 | } | ||
443 | } | ||
diff --git a/lib/python/qmk/cli/c2json.py b/lib/python/qmk/cli/c2json.py index b9d55ebdb..a97e21222 100644 --- a/lib/python/qmk/cli/c2json.py +++ b/lib/python/qmk/cli/c2json.py | |||
@@ -7,12 +7,13 @@ from milc import cli | |||
7 | import qmk.keymap | 7 | import qmk.keymap |
8 | import qmk.path | 8 | import qmk.path |
9 | from qmk.info_json_encoder import InfoJSONEncoder | 9 | from qmk.info_json_encoder import InfoJSONEncoder |
10 | from qmk.keyboard import keyboard_folder | ||
10 | 11 | ||
11 | 12 | ||
12 | @cli.argument('--no-cpp', arg_only=True, action='store_false', help='Do not use \'cpp\' on keymap.c') | 13 | @cli.argument('--no-cpp', arg_only=True, action='store_false', help='Do not use \'cpp\' on keymap.c') |
13 | @cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') | 14 | @cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') |
14 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") | 15 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") |
15 | @cli.argument('-kb', '--keyboard', arg_only=True, required=True, help='The keyboard\'s name') | 16 | @cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, required=True, help='The keyboard\'s name') |
16 | @cli.argument('-km', '--keymap', arg_only=True, required=True, help='The keymap\'s name') | 17 | @cli.argument('-km', '--keymap', arg_only=True, required=True, help='The keymap\'s name') |
17 | @cli.argument('filename', arg_only=True, help='keymap.c file') | 18 | @cli.argument('filename', arg_only=True, help='keymap.c file') |
18 | @cli.subcommand('Creates a keymap.json from a keymap.c file.') | 19 | @cli.subcommand('Creates a keymap.json from a keymap.c file.') |
diff --git a/lib/python/qmk/cli/compile.py b/lib/python/qmk/cli/compile.py index db195f78a..5793e9892 100755 --- a/lib/python/qmk/cli/compile.py +++ b/lib/python/qmk/cli/compile.py | |||
@@ -7,10 +7,11 @@ from milc import cli | |||
7 | import qmk.path | 7 | import qmk.path |
8 | from qmk.decorators import automagic_keyboard, automagic_keymap | 8 | from qmk.decorators import automagic_keyboard, automagic_keymap |
9 | from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json | 9 | from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json |
10 | from qmk.keyboard import keyboard_folder | ||
10 | 11 | ||
11 | 12 | ||
12 | @cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), help='The configurator export to compile') | 13 | @cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), help='The configurator export to compile') |
13 | @cli.argument('-kb', '--keyboard', help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.') | 14 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.') |
14 | @cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Ignored when a configurator export is supplied.') | 15 | @cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Ignored when a configurator export is supplied.') |
15 | @cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.") | 16 | @cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.") |
16 | @cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.") | 17 | @cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.") |
diff --git a/lib/python/qmk/cli/flash.py b/lib/python/qmk/cli/flash.py index 173dee3df..c9273c3f9 100644 --- a/lib/python/qmk/cli/flash.py +++ b/lib/python/qmk/cli/flash.py | |||
@@ -9,6 +9,7 @@ from milc import cli | |||
9 | import qmk.path | 9 | import qmk.path |
10 | from qmk.decorators import automagic_keyboard, automagic_keymap | 10 | from qmk.decorators import automagic_keyboard, automagic_keymap |
11 | from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json | 11 | from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json |
12 | from qmk.keyboard import keyboard_folder | ||
12 | 13 | ||
13 | 14 | ||
14 | def print_bootloader_help(): | 15 | def print_bootloader_help(): |
@@ -33,7 +34,7 @@ def print_bootloader_help(): | |||
33 | @cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.') | 34 | @cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.') |
34 | @cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.') | 35 | @cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.') |
35 | @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.') | 36 | @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.') |
36 | @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.') | 37 | @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.') |
37 | @cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.") | 38 | @cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.") |
38 | @cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.") | 39 | @cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.") |
39 | @cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.") | 40 | @cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.") |
diff --git a/lib/python/qmk/cli/generate/api.py b/lib/python/qmk/cli/generate/api.py index 6d111f244..9870f7201 100755 --- a/lib/python/qmk/cli/generate/api.py +++ b/lib/python/qmk/cli/generate/api.py | |||
@@ -9,6 +9,7 @@ from milc import cli | |||
9 | from qmk.datetime import current_datetime | 9 | from qmk.datetime import current_datetime |
10 | from qmk.info import info_json | 10 | from qmk.info import info_json |
11 | from qmk.info_json_encoder import InfoJSONEncoder | 11 | from qmk.info_json_encoder import InfoJSONEncoder |
12 | from qmk.json_schema import json_load | ||
12 | from qmk.keyboard import list_keyboards | 13 | from qmk.keyboard import list_keyboards |
13 | 14 | ||
14 | 15 | ||
@@ -18,43 +19,58 @@ def generate_api(cli): | |||
18 | """ | 19 | """ |
19 | api_data_dir = Path('api_data') | 20 | api_data_dir = Path('api_data') |
20 | v1_dir = api_data_dir / 'v1' | 21 | v1_dir = api_data_dir / 'v1' |
21 | keyboard_list = v1_dir / 'keyboard_list.json' | 22 | keyboard_all_file = v1_dir / 'keyboards.json' # A massive JSON containing everything |
22 | keyboard_all = v1_dir / 'keyboards.json' | 23 | keyboard_list_file = v1_dir / 'keyboard_list.json' # A simple list of keyboard targets |
23 | usb_file = v1_dir / 'usb.json' | 24 | keyboard_aliases_file = v1_dir / 'keyboard_aliases.json' # A list of historical keyboard names and their new name |
25 | keyboard_metadata_file = v1_dir / 'keyboard_metadata.json' # All the data configurator/via needs for initialization | ||
26 | usb_file = v1_dir / 'usb.json' # A mapping of USB VID/PID -> keyboard target | ||
24 | 27 | ||
25 | if not api_data_dir.exists(): | 28 | if not api_data_dir.exists(): |
26 | api_data_dir.mkdir() | 29 | api_data_dir.mkdir() |
27 | 30 | ||
28 | kb_all = {'last_updated': current_datetime(), 'keyboards': {}} | 31 | kb_all = {} |
29 | usb_list = {'last_updated': current_datetime(), 'devices': {}} | 32 | usb_list = {} |
30 | 33 | ||
31 | # Generate and write keyboard specific JSON files | 34 | # Generate and write keyboard specific JSON files |
32 | for keyboard_name in list_keyboards(): | 35 | for keyboard_name in list_keyboards(): |
33 | kb_all['keyboards'][keyboard_name] = info_json(keyboard_name) | 36 | kb_all[keyboard_name] = info_json(keyboard_name) |
34 | keyboard_dir = v1_dir / 'keyboards' / keyboard_name | 37 | keyboard_dir = v1_dir / 'keyboards' / keyboard_name |
35 | keyboard_info = keyboard_dir / 'info.json' | 38 | keyboard_info = keyboard_dir / 'info.json' |
36 | keyboard_readme = keyboard_dir / 'readme.md' | 39 | keyboard_readme = keyboard_dir / 'readme.md' |
37 | keyboard_readme_src = Path('keyboards') / keyboard_name / 'readme.md' | 40 | keyboard_readme_src = Path('keyboards') / keyboard_name / 'readme.md' |
38 | 41 | ||
39 | keyboard_dir.mkdir(parents=True, exist_ok=True) | 42 | keyboard_dir.mkdir(parents=True, exist_ok=True) |
40 | keyboard_info.write_text(json.dumps({'last_updated': current_datetime(), 'keyboards': {keyboard_name: kb_all['keyboards'][keyboard_name]}})) | 43 | keyboard_info.write_text(json.dumps({'last_updated': current_datetime(), 'keyboards': {keyboard_name: kb_all[keyboard_name]}})) |
41 | 44 | ||
42 | if keyboard_readme_src.exists(): | 45 | if keyboard_readme_src.exists(): |
43 | copyfile(keyboard_readme_src, keyboard_readme) | 46 | copyfile(keyboard_readme_src, keyboard_readme) |
44 | 47 | ||
45 | if 'usb' in kb_all['keyboards'][keyboard_name]: | 48 | if 'usb' in kb_all[keyboard_name]: |
46 | usb = kb_all['keyboards'][keyboard_name]['usb'] | 49 | usb = kb_all[keyboard_name]['usb'] |
47 | 50 | ||
48 | if 'vid' in usb and usb['vid'] not in usb_list['devices']: | 51 | if 'vid' in usb and usb['vid'] not in usb_list: |
49 | usb_list['devices'][usb['vid']] = {} | 52 | usb_list[usb['vid']] = {} |
50 | 53 | ||
51 | if 'pid' in usb and usb['pid'] not in usb_list['devices'][usb['vid']]: | 54 | if 'pid' in usb and usb['pid'] not in usb_list[usb['vid']]: |
52 | usb_list['devices'][usb['vid']][usb['pid']] = {} | 55 | usb_list[usb['vid']][usb['pid']] = {} |
53 | 56 | ||
54 | if 'vid' in usb and 'pid' in usb: | 57 | if 'vid' in usb and 'pid' in usb: |
55 | usb_list['devices'][usb['vid']][usb['pid']][keyboard_name] = usb | 58 | usb_list[usb['vid']][usb['pid']][keyboard_name] = usb |
56 | 59 | ||
57 | # Write the global JSON files | 60 | # Write the global JSON files |
58 | keyboard_list.write_text(json.dumps({'last_updated': current_datetime(), 'keyboards': sorted(kb_all['keyboards'])}, cls=InfoJSONEncoder)) | 61 | keyboard_all_file.write_text(json.dumps({'last_updated': current_datetime(), 'keyboards': kb_all}, cls=InfoJSONEncoder)) |
59 | keyboard_all.write_text(json.dumps(kb_all, cls=InfoJSONEncoder)) | 62 | usb_file.write_text(json.dumps({'last_updated': current_datetime(), 'usb': usb_list}, cls=InfoJSONEncoder)) |
60 | usb_file.write_text(json.dumps(usb_list, cls=InfoJSONEncoder)) | 63 | |
64 | keyboard_list = sorted(kb_all) | ||
65 | keyboard_list_file.write_text(json.dumps({'last_updated': current_datetime(), 'keyboards': keyboard_list}, cls=InfoJSONEncoder)) | ||
66 | |||
67 | keyboard_aliases = json_load(Path('data/mappings/keyboard_aliases.json')) | ||
68 | keyboard_aliases_file.write_text(json.dumps({'last_updated': current_datetime(), 'keyboard_aliases': keyboard_aliases}, cls=InfoJSONEncoder)) | ||
69 | |||
70 | keyboard_metadata = { | ||
71 | 'last_updated': current_datetime(), | ||
72 | 'keyboards': keyboard_list, | ||
73 | 'keyboard_aliases': keyboard_aliases, | ||
74 | 'usb': usb_list | ||
75 | } | ||
76 | keyboard_metadata_file.write_text(json.dumps(keyboard_metadata, cls=InfoJSONEncoder)) | ||
diff --git a/lib/python/qmk/cli/generate/config_h.py b/lib/python/qmk/cli/generate/config_h.py index e6d49ea4d..ccea6d7a0 100755 --- a/lib/python/qmk/cli/generate/config_h.py +++ b/lib/python/qmk/cli/generate/config_h.py | |||
@@ -6,7 +6,9 @@ from dotty_dict import dotty | |||
6 | from milc import cli | 6 | from milc import cli |
7 | 7 | ||
8 | from qmk.decorators import automagic_keyboard, automagic_keymap | 8 | from qmk.decorators import automagic_keyboard, automagic_keymap |
9 | from qmk.info import _json_load, info_json | 9 | from qmk.info import info_json |
10 | from qmk.json_schema import json_load | ||
11 | from qmk.keyboard import keyboard_folder | ||
10 | from qmk.path import is_keyboard, normpath | 12 | from qmk.path import is_keyboard, normpath |
11 | 13 | ||
12 | 14 | ||
@@ -73,7 +75,7 @@ def matrix_pins(matrix_pins): | |||
73 | 75 | ||
74 | @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') | 76 | @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') |
75 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") | 77 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") |
76 | @cli.argument('-kb', '--keyboard', help='Keyboard to generate config.h for.') | 78 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to generate config.h for.') |
77 | @cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True) | 79 | @cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True) |
78 | @automagic_keyboard | 80 | @automagic_keyboard |
79 | @automagic_keymap | 81 | @automagic_keymap |
@@ -92,7 +94,7 @@ def generate_config_h(cli): | |||
92 | 94 | ||
93 | # Build the info_config.h file. | 95 | # Build the info_config.h file. |
94 | kb_info_json = dotty(info_json(cli.config.generate_config_h.keyboard)) | 96 | kb_info_json = dotty(info_json(cli.config.generate_config_h.keyboard)) |
95 | info_config_map = _json_load(Path('data/mappings/info_config.json')) | 97 | info_config_map = json_load(Path('data/mappings/info_config.json')) |
96 | 98 | ||
97 | config_h_lines = ['/* This file was generated by `qmk generate-config-h`. Do not edit or copy.' ' */', '', '#pragma once'] | 99 | config_h_lines = ['/* This file was generated by `qmk generate-config-h`. Do not edit or copy.' ' */', '', '#pragma once'] |
98 | 100 | ||
diff --git a/lib/python/qmk/cli/generate/info_json.py b/lib/python/qmk/cli/generate/info_json.py index f3fc54ddc..6c00ba7d8 100755 --- a/lib/python/qmk/cli/generate/info_json.py +++ b/lib/python/qmk/cli/generate/info_json.py | |||
@@ -8,8 +8,10 @@ from jsonschema import Draft7Validator, validators | |||
8 | from milc import cli | 8 | from milc import cli |
9 | 9 | ||
10 | from qmk.decorators import automagic_keyboard, automagic_keymap | 10 | from qmk.decorators import automagic_keyboard, automagic_keymap |
11 | from qmk.info import info_json, _jsonschema | 11 | from qmk.info import info_json |
12 | from qmk.info_json_encoder import InfoJSONEncoder | 12 | from qmk.info_json_encoder import InfoJSONEncoder |
13 | from qmk.json_schema import load_jsonschema | ||
14 | from qmk.keyboard import keyboard_folder | ||
13 | from qmk.path import is_keyboard | 15 | from qmk.path import is_keyboard |
14 | 16 | ||
15 | 17 | ||
@@ -33,13 +35,13 @@ def strip_info_json(kb_info_json): | |||
33 | """Remove the API-only properties from the info.json. | 35 | """Remove the API-only properties from the info.json. |
34 | """ | 36 | """ |
35 | pruning_draft_7_validator = pruning_validator(Draft7Validator) | 37 | pruning_draft_7_validator = pruning_validator(Draft7Validator) |
36 | schema = _jsonschema('keyboard') | 38 | schema = load_jsonschema('keyboard') |
37 | validator = pruning_draft_7_validator(schema).validate | 39 | validator = pruning_draft_7_validator(schema).validate |
38 | 40 | ||
39 | return validator(kb_info_json) | 41 | return validator(kb_info_json) |
40 | 42 | ||
41 | 43 | ||
42 | @cli.argument('-kb', '--keyboard', help='Keyboard to show info for.') | 44 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to show info for.') |
43 | @cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.') | 45 | @cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.') |
44 | @cli.subcommand('Generate an info.json file for a keyboard.', hidden=False if cli.config.user.developer else True) | 46 | @cli.subcommand('Generate an info.json file for a keyboard.', hidden=False if cli.config.user.developer else True) |
45 | @automagic_keyboard | 47 | @automagic_keyboard |
diff --git a/lib/python/qmk/cli/generate/layouts.py b/lib/python/qmk/cli/generate/layouts.py index a738edfe6..7b4394291 100755 --- a/lib/python/qmk/cli/generate/layouts.py +++ b/lib/python/qmk/cli/generate/layouts.py | |||
@@ -5,6 +5,7 @@ from milc import cli | |||
5 | from qmk.constants import COL_LETTERS, ROW_LETTERS | 5 | from qmk.constants import COL_LETTERS, ROW_LETTERS |
6 | from qmk.decorators import automagic_keyboard, automagic_keymap | 6 | from qmk.decorators import automagic_keyboard, automagic_keymap |
7 | from qmk.info import info_json | 7 | from qmk.info import info_json |
8 | from qmk.keyboard import keyboard_folder | ||
8 | from qmk.path import is_keyboard, normpath | 9 | from qmk.path import is_keyboard, normpath |
9 | 10 | ||
10 | usb_properties = { | 11 | usb_properties = { |
@@ -16,7 +17,7 @@ usb_properties = { | |||
16 | 17 | ||
17 | @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') | 18 | @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') |
18 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") | 19 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") |
19 | @cli.argument('-kb', '--keyboard', help='Keyboard to generate config.h for.') | 20 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to generate config.h for.') |
20 | @cli.subcommand('Used by the make system to generate layouts.h from info.json', hidden=True) | 21 | @cli.subcommand('Used by the make system to generate layouts.h from info.json', hidden=True) |
21 | @automagic_keyboard | 22 | @automagic_keyboard |
22 | @automagic_keymap | 23 | @automagic_keymap |
diff --git a/lib/python/qmk/cli/generate/rules_mk.py b/lib/python/qmk/cli/generate/rules_mk.py index 15917987b..91759d26c 100755 --- a/lib/python/qmk/cli/generate/rules_mk.py +++ b/lib/python/qmk/cli/generate/rules_mk.py | |||
@@ -6,7 +6,9 @@ from dotty_dict import dotty | |||
6 | from milc import cli | 6 | from milc import cli |
7 | 7 | ||
8 | from qmk.decorators import automagic_keyboard, automagic_keymap | 8 | from qmk.decorators import automagic_keyboard, automagic_keymap |
9 | from qmk.info import _json_load, info_json | 9 | from qmk.info import info_json |
10 | from qmk.json_schema import json_load | ||
11 | from qmk.keyboard import keyboard_folder | ||
10 | from qmk.path import is_keyboard, normpath | 12 | from qmk.path import is_keyboard, normpath |
11 | 13 | ||
12 | 14 | ||
@@ -37,7 +39,7 @@ def process_mapping_rule(kb_info_json, rules_key, info_dict): | |||
37 | @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') | 39 | @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') |
38 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") | 40 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") |
39 | @cli.argument('-e', '--escape', arg_only=True, action='store_true', help="Escape spaces in quiet mode") | 41 | @cli.argument('-e', '--escape', arg_only=True, action='store_true', help="Escape spaces in quiet mode") |
40 | @cli.argument('-kb', '--keyboard', help='Keyboard to generate config.h for.') | 42 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to generate config.h for.') |
41 | @cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True) | 43 | @cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True) |
42 | @automagic_keyboard | 44 | @automagic_keyboard |
43 | @automagic_keymap | 45 | @automagic_keymap |
@@ -54,7 +56,7 @@ def generate_rules_mk(cli): | |||
54 | return False | 56 | return False |
55 | 57 | ||
56 | kb_info_json = dotty(info_json(cli.config.generate_rules_mk.keyboard)) | 58 | kb_info_json = dotty(info_json(cli.config.generate_rules_mk.keyboard)) |
57 | info_rules_map = _json_load(Path('data/mappings/info_rules.json')) | 59 | info_rules_map = json_load(Path('data/mappings/info_rules.json')) |
58 | rules_mk_lines = ['# This file was generated by `qmk generate-rules-mk`. Do not edit or copy.', ''] | 60 | rules_mk_lines = ['# This file was generated by `qmk generate-rules-mk`. Do not edit or copy.', ''] |
59 | 61 | ||
60 | # Iterate through the info_rules map to generate basic rules | 62 | # Iterate through the info_rules map to generate basic rules |
diff --git a/lib/python/qmk/cli/info.py b/lib/python/qmk/cli/info.py index a7ce8abf0..88b65686f 100755 --- a/lib/python/qmk/cli/info.py +++ b/lib/python/qmk/cli/info.py | |||
@@ -10,7 +10,7 @@ from milc import cli | |||
10 | from qmk.info_json_encoder import InfoJSONEncoder | 10 | from qmk.info_json_encoder import InfoJSONEncoder |
11 | from qmk.constants import COL_LETTERS, ROW_LETTERS | 11 | from qmk.constants import COL_LETTERS, ROW_LETTERS |
12 | from qmk.decorators import automagic_keyboard, automagic_keymap | 12 | from qmk.decorators import automagic_keyboard, automagic_keymap |
13 | from qmk.keyboard import render_layouts, render_layout | 13 | from qmk.keyboard import keyboard_folder, render_layouts, render_layout |
14 | from qmk.keymap import locate_keymap | 14 | from qmk.keymap import locate_keymap |
15 | from qmk.info import info_json | 15 | from qmk.info import info_json |
16 | from qmk.path import is_keyboard | 16 | from qmk.path import is_keyboard |
@@ -124,7 +124,7 @@ def print_text_output(kb_info_json): | |||
124 | show_keymap(kb_info_json, False) | 124 | show_keymap(kb_info_json, False) |
125 | 125 | ||
126 | 126 | ||
127 | @cli.argument('-kb', '--keyboard', help='Keyboard to show info for.') | 127 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Keyboard to show info for.') |
128 | @cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.') | 128 | @cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.') |
129 | @cli.argument('-l', '--layouts', action='store_true', help='Render the layouts.') | 129 | @cli.argument('-l', '--layouts', action='store_true', help='Render the layouts.') |
130 | @cli.argument('-m', '--matrix', action='store_true', help='Render the layouts with matrix information.') | 130 | @cli.argument('-m', '--matrix', action='store_true', help='Render the layouts with matrix information.') |
diff --git a/lib/python/qmk/cli/list/keymaps.py b/lib/python/qmk/cli/list/keymaps.py index 49bc84b2c..7c0ad4399 100644 --- a/lib/python/qmk/cli/list/keymaps.py +++ b/lib/python/qmk/cli/list/keymaps.py | |||
@@ -4,18 +4,14 @@ from milc import cli | |||
4 | 4 | ||
5 | import qmk.keymap | 5 | import qmk.keymap |
6 | from qmk.decorators import automagic_keyboard | 6 | from qmk.decorators import automagic_keyboard |
7 | from qmk.path import is_keyboard | 7 | from qmk.keyboard import keyboard_folder |
8 | 8 | ||
9 | 9 | ||
10 | @cli.argument("-kb", "--keyboard", help="Specify keyboard name. Example: 1upkeyboards/1up60hse") | 10 | @cli.argument("-kb", "--keyboard", type=keyboard_folder, help="Specify keyboard name. Example: 1upkeyboards/1up60hse") |
11 | @cli.subcommand("List the keymaps for a specific keyboard") | 11 | @cli.subcommand("List the keymaps for a specific keyboard") |
12 | @automagic_keyboard | 12 | @automagic_keyboard |
13 | def list_keymaps(cli): | 13 | def list_keymaps(cli): |
14 | """List the keymaps for a specific keyboard | 14 | """List the keymaps for a specific keyboard |
15 | """ | 15 | """ |
16 | if not is_keyboard(cli.config.list_keymaps.keyboard): | ||
17 | cli.log.error('Keyboard %s does not exist!', cli.config.list_keymaps.keyboard) | ||
18 | return False | ||
19 | |||
20 | for name in qmk.keymap.list_keymaps(cli.config.list_keymaps.keyboard): | 16 | for name in qmk.keymap.list_keymaps(cli.config.list_keymaps.keyboard): |
21 | print(name) | 17 | print(name) |
diff --git a/lib/python/qmk/cli/new/keymap.py b/lib/python/qmk/cli/new/keymap.py index 52c564997..ea98a287c 100755 --- a/lib/python/qmk/cli/new/keymap.py +++ b/lib/python/qmk/cli/new/keymap.py | |||
@@ -5,10 +5,11 @@ from pathlib import Path | |||
5 | 5 | ||
6 | import qmk.path | 6 | import qmk.path |
7 | from qmk.decorators import automagic_keyboard, automagic_keymap | 7 | from qmk.decorators import automagic_keyboard, automagic_keymap |
8 | from qmk.keyboard import keyboard_folder | ||
8 | from milc import cli | 9 | from milc import cli |
9 | 10 | ||
10 | 11 | ||
11 | @cli.argument('-kb', '--keyboard', help='Specify keyboard name. Example: 1upkeyboards/1up60hse') | 12 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, help='Specify keyboard name. Example: 1upkeyboards/1up60hse') |
12 | @cli.argument('-km', '--keymap', help='Specify the name for the new keymap directory') | 13 | @cli.argument('-km', '--keymap', help='Specify the name for the new keymap directory') |
13 | @cli.subcommand('Creates a new keymap for the keyboard of your choosing') | 14 | @cli.subcommand('Creates a new keymap for the keyboard of your choosing') |
14 | @automagic_keyboard | 15 | @automagic_keyboard |
diff --git a/lib/python/qmk/commands.py b/lib/python/qmk/commands.py index 4809365af..510abffdc 100644 --- a/lib/python/qmk/commands.py +++ b/lib/python/qmk/commands.py | |||
@@ -13,6 +13,7 @@ from milc import cli | |||
13 | 13 | ||
14 | import qmk.keymap | 14 | import qmk.keymap |
15 | from qmk.constants import KEYBOARD_OUTPUT_PREFIX | 15 | from qmk.constants import KEYBOARD_OUTPUT_PREFIX |
16 | from qmk.json_schema import json_load | ||
16 | 17 | ||
17 | time_fmt = '%Y-%m-%d-%H:%M:%S' | 18 | time_fmt = '%Y-%m-%d-%H:%M:%S' |
18 | 19 | ||
@@ -191,6 +192,15 @@ def parse_configurator_json(configurator_file): | |||
191 | """ | 192 | """ |
192 | # FIXME(skullydazed/anyone): Add validation here | 193 | # FIXME(skullydazed/anyone): Add validation here |
193 | user_keymap = json.load(configurator_file) | 194 | user_keymap = json.load(configurator_file) |
195 | orig_keyboard = user_keymap['keyboard'] | ||
196 | aliases = json_load(Path('data/mappings/keyboard_aliases.json')) | ||
197 | |||
198 | if orig_keyboard in aliases: | ||
199 | if 'target' in aliases[orig_keyboard]: | ||
200 | user_keymap['keyboard'] = aliases[orig_keyboard]['target'] | ||
201 | |||
202 | if 'layouts' in aliases[orig_keyboard] and user_keymap['layout'] in aliases[orig_keyboard]['layouts']: | ||
203 | user_keymap['layout'] = aliases[orig_keyboard]['layouts'][user_keymap['layout']] | ||
194 | 204 | ||
195 | return user_keymap | 205 | return user_keymap |
196 | 206 | ||
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py index 60d3a0132..e2350b7f7 100644 --- a/lib/python/qmk/info.py +++ b/lib/python/qmk/info.py | |||
@@ -1,17 +1,15 @@ | |||
1 | """Functions that help us generate and use info.json files. | 1 | """Functions that help us generate and use info.json files. |
2 | """ | 2 | """ |
3 | import json | ||
4 | from collections.abc import Mapping | ||
5 | from glob import glob | 3 | from glob import glob |
6 | from pathlib import Path | 4 | from pathlib import Path |
7 | 5 | ||
8 | import hjson | ||
9 | import jsonschema | 6 | import jsonschema |
10 | from dotty_dict import dotty | 7 | from dotty_dict import dotty |
11 | from milc import cli | 8 | from milc import cli |
12 | 9 | ||
13 | from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS | 10 | from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS |
14 | from qmk.c_parse import find_layouts | 11 | from qmk.c_parse import find_layouts |
12 | from qmk.json_schema import deep_update, json_load, keyboard_validate, keyboard_api_validate | ||
15 | from qmk.keyboard import config_h, rules_mk | 13 | from qmk.keyboard import config_h, rules_mk |
16 | from qmk.keymap import list_keymaps | 14 | from qmk.keymap import list_keymaps |
17 | from qmk.makefile import parse_rules_mk_file | 15 | from qmk.makefile import parse_rules_mk_file |
@@ -82,52 +80,6 @@ def info_json(keyboard): | |||
82 | return info_data | 80 | return info_data |
83 | 81 | ||
84 | 82 | ||
85 | def _json_load(json_file): | ||
86 | """Load a json file from disk. | ||
87 | |||
88 | Note: file must be a Path object. | ||
89 | """ | ||
90 | try: | ||
91 | return hjson.load(json_file.open(encoding='utf-8')) | ||
92 | |||
93 | except json.decoder.JSONDecodeError as e: | ||
94 | cli.log.error('Invalid JSON encountered attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e) | ||
95 | exit(1) | ||
96 | |||
97 | |||
98 | def _jsonschema(schema_name): | ||
99 | """Read a jsonschema file from disk. | ||
100 | |||
101 | FIXME(skullydazed/anyone): Refactor to make this a public function. | ||
102 | """ | ||
103 | schema_path = Path(f'data/schemas/{schema_name}.jsonschema') | ||
104 | |||
105 | if not schema_path.exists(): | ||
106 | schema_path = Path('data/schemas/false.jsonschema') | ||
107 | |||
108 | return _json_load(schema_path) | ||
109 | |||
110 | |||
111 | def keyboard_validate(data): | ||
112 | """Validates data against the keyboard jsonschema. | ||
113 | """ | ||
114 | schema = _jsonschema('keyboard') | ||
115 | validator = jsonschema.Draft7Validator(schema).validate | ||
116 | |||
117 | return validator(data) | ||
118 | |||
119 | |||
120 | def keyboard_api_validate(data): | ||
121 | """Validates data against the api_keyboard jsonschema. | ||
122 | """ | ||
123 | base = _jsonschema('keyboard') | ||
124 | relative = _jsonschema('api_keyboard') | ||
125 | resolver = jsonschema.RefResolver.from_schema(base) | ||
126 | validator = jsonschema.Draft7Validator(relative, resolver=resolver).validate | ||
127 | |||
128 | return validator(data) | ||
129 | |||
130 | |||
131 | def _extract_features(info_data, rules): | 83 | def _extract_features(info_data, rules): |
132 | """Find all the features enabled in rules.mk. | 84 | """Find all the features enabled in rules.mk. |
133 | """ | 85 | """ |
@@ -258,7 +210,7 @@ def _extract_config_h(info_data): | |||
258 | 210 | ||
259 | # Pull in data from the json map | 211 | # Pull in data from the json map |
260 | dotty_info = dotty(info_data) | 212 | dotty_info = dotty(info_data) |
261 | info_config_map = _json_load(Path('data/mappings/info_config.json')) | 213 | info_config_map = json_load(Path('data/mappings/info_config.json')) |
262 | 214 | ||
263 | for config_key, info_dict in info_config_map.items(): | 215 | for config_key, info_dict in info_config_map.items(): |
264 | info_key = info_dict['info_key'] | 216 | info_key = info_dict['info_key'] |
@@ -326,7 +278,7 @@ def _extract_rules_mk(info_data): | |||
326 | 278 | ||
327 | # Pull in data from the json map | 279 | # Pull in data from the json map |
328 | dotty_info = dotty(info_data) | 280 | dotty_info = dotty(info_data) |
329 | info_rules_map = _json_load(Path('data/mappings/info_rules.json')) | 281 | info_rules_map = json_load(Path('data/mappings/info_rules.json')) |
330 | 282 | ||
331 | for rules_key, info_dict in info_rules_map.items(): | 283 | for rules_key, info_dict in info_rules_map.items(): |
332 | info_key = info_dict['info_key'] | 284 | info_key = info_dict['info_key'] |
@@ -516,25 +468,12 @@ def unknown_processor_rules(info_data, rules): | |||
516 | return info_data | 468 | return info_data |
517 | 469 | ||
518 | 470 | ||
519 | def deep_update(origdict, newdict): | ||
520 | """Update a dictionary in place, recursing to do a deep copy. | ||
521 | """ | ||
522 | for key, value in newdict.items(): | ||
523 | if isinstance(value, Mapping): | ||
524 | origdict[key] = deep_update(origdict.get(key, {}), value) | ||
525 | |||
526 | else: | ||
527 | origdict[key] = value | ||
528 | |||
529 | return origdict | ||
530 | |||
531 | |||
532 | def merge_info_jsons(keyboard, info_data): | 471 | def merge_info_jsons(keyboard, info_data): |
533 | """Return a merged copy of all the info.json files for a keyboard. | 472 | """Return a merged copy of all the info.json files for a keyboard. |
534 | """ | 473 | """ |
535 | for info_file in find_info_json(keyboard): | 474 | for info_file in find_info_json(keyboard): |
536 | # Load and validate the JSON data | 475 | # Load and validate the JSON data |
537 | new_info_data = _json_load(info_file) | 476 | new_info_data = json_load(info_file) |
538 | 477 | ||
539 | if not isinstance(new_info_data, dict): | 478 | if not isinstance(new_info_data, dict): |
540 | _log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),)) | 479 | _log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),)) |
diff --git a/lib/python/qmk/json_schema.py b/lib/python/qmk/json_schema.py new file mode 100644 index 000000000..b4cd1776b --- /dev/null +++ b/lib/python/qmk/json_schema.py | |||
@@ -0,0 +1,68 @@ | |||
1 | """Functions that help us generate and use info.json files. | ||
2 | """ | ||
3 | import json | ||
4 | from collections.abc import Mapping | ||
5 | from pathlib import Path | ||
6 | |||
7 | import hjson | ||
8 | import jsonschema | ||
9 | from milc import cli | ||
10 | |||
11 | |||
12 | def json_load(json_file): | ||
13 | """Load a json file from disk. | ||
14 | |||
15 | Note: file must be a Path object. | ||
16 | """ | ||
17 | try: | ||
18 | return hjson.load(json_file.open()) | ||
19 | |||
20 | except json.decoder.JSONDecodeError as e: | ||
21 | cli.log.error('Invalid JSON encountered attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e) | ||
22 | exit(1) | ||
23 | |||
24 | |||
25 | def load_jsonschema(schema_name): | ||
26 | """Read a jsonschema file from disk. | ||
27 | |||
28 | FIXME(skullydazed/anyone): Refactor to make this a public function. | ||
29 | """ | ||
30 | schema_path = Path(f'data/schemas/{schema_name}.jsonschema') | ||
31 | |||
32 | if not schema_path.exists(): | ||
33 | schema_path = Path('data/schemas/false.jsonschema') | ||
34 | |||
35 | return json_load(schema_path) | ||
36 | |||
37 | |||
38 | def keyboard_validate(data): | ||
39 | """Validates data against the keyboard jsonschema. | ||
40 | """ | ||
41 | schema = load_jsonschema('keyboard') | ||
42 | validator = jsonschema.Draft7Validator(schema).validate | ||
43 | |||
44 | return validator(data) | ||
45 | |||
46 | |||
47 | def keyboard_api_validate(data): | ||
48 | """Validates data against the api_keyboard jsonschema. | ||
49 | """ | ||
50 | base = load_jsonschema('keyboard') | ||
51 | relative = load_jsonschema('api_keyboard') | ||
52 | resolver = jsonschema.RefResolver.from_schema(base) | ||
53 | validator = jsonschema.Draft7Validator(relative, resolver=resolver).validate | ||
54 | |||
55 | return validator(data) | ||
56 | |||
57 | |||
58 | def deep_update(origdict, newdict): | ||
59 | """Update a dictionary in place, recursing to do a deep copy. | ||
60 | """ | ||
61 | for key, value in newdict.items(): | ||
62 | if isinstance(value, Mapping): | ||
63 | origdict[key] = deep_update(origdict.get(key, {}), value) | ||
64 | |||
65 | else: | ||
66 | origdict[key] = value | ||
67 | |||
68 | return origdict | ||
diff --git a/lib/python/qmk/keyboard.py b/lib/python/qmk/keyboard.py index a4c287375..89f9346c4 100644 --- a/lib/python/qmk/keyboard.py +++ b/lib/python/qmk/keyboard.py | |||
@@ -7,7 +7,9 @@ import os | |||
7 | from glob import glob | 7 | from glob import glob |
8 | 8 | ||
9 | from qmk.c_parse import parse_config_h_file | 9 | from qmk.c_parse import parse_config_h_file |
10 | from qmk.json_schema import json_load | ||
10 | from qmk.makefile import parse_rules_mk_file | 11 | from qmk.makefile import parse_rules_mk_file |
12 | from qmk.path import is_keyboard | ||
11 | 13 | ||
12 | BOX_DRAWING_CHARACTERS = { | 14 | BOX_DRAWING_CHARACTERS = { |
13 | "unicode": { | 15 | "unicode": { |
@@ -31,6 +33,28 @@ BOX_DRAWING_CHARACTERS = { | |||
31 | base_path = os.path.join(os.getcwd(), "keyboards") + os.path.sep | 33 | base_path = os.path.join(os.getcwd(), "keyboards") + os.path.sep |
32 | 34 | ||
33 | 35 | ||
36 | def keyboard_folder(keyboard): | ||
37 | """Returns the actual keyboard folder. | ||
38 | |||
39 | This checks aliases and DEFAULT_FOLDER to resolve the actual path for a keyboard. | ||
40 | """ | ||
41 | aliases = json_load(Path('data/mappings/keyboard_aliases.json')) | ||
42 | |||
43 | if keyboard in aliases: | ||
44 | keyboard = aliases[keyboard].get('target', keyboard) | ||
45 | |||
46 | rules_mk_file = Path(base_path, keyboard, 'rules.mk') | ||
47 | |||
48 | if rules_mk_file.exists(): | ||
49 | rules_mk = parse_rules_mk_file(rules_mk_file) | ||
50 | keyboard = rules_mk.get('DEFAULT_FOLDER', keyboard) | ||
51 | |||
52 | if not is_keyboard(keyboard): | ||
53 | raise ValueError(f'Invalid keyboard: {keyboard}') | ||
54 | |||
55 | return keyboard | ||
56 | |||
57 | |||
34 | def _find_name(path): | 58 | def _find_name(path): |
35 | """Determine the keyboard name by stripping off the base_path and rules.mk. | 59 | """Determine the keyboard name by stripping off the base_path and rules.mk. |
36 | """ | 60 | """ |
diff --git a/lib/python/qmk/path.py b/lib/python/qmk/path.py index 2aa1916f5..72bae5927 100644 --- a/lib/python/qmk/path.py +++ b/lib/python/qmk/path.py | |||
@@ -15,6 +15,7 @@ def is_keyboard(keyboard_name): | |||
15 | if keyboard_name: | 15 | if keyboard_name: |
16 | keyboard_path = QMK_FIRMWARE / 'keyboards' / keyboard_name | 16 | keyboard_path = QMK_FIRMWARE / 'keyboards' / keyboard_name |
17 | rules_mk = keyboard_path / 'rules.mk' | 17 | rules_mk = keyboard_path / 'rules.mk' |
18 | |||
18 | return rules_mk.exists() | 19 | return rules_mk.exists() |
19 | 20 | ||
20 | 21 | ||
diff --git a/lib/python/qmk/tests/test_cli_commands.py b/lib/python/qmk/tests/test_cli_commands.py index bfecebdd7..b16777e54 100644 --- a/lib/python/qmk/tests/test_cli_commands.py +++ b/lib/python/qmk/tests/test_cli_commands.py | |||
@@ -134,8 +134,8 @@ def test_list_keymaps_vendor_kb_rev(): | |||
134 | 134 | ||
135 | def test_list_keymaps_no_keyboard_found(): | 135 | def test_list_keymaps_no_keyboard_found(): |
136 | result = check_subcommand('list-keymaps', '-kb', 'asdfghjkl') | 136 | result = check_subcommand('list-keymaps', '-kb', 'asdfghjkl') |
137 | check_returncode(result, [1]) | 137 | check_returncode(result, [2]) |
138 | assert 'does not exist' in result.stdout | 138 | assert 'invalid keyboard_folder value' in result.stdout |
139 | 139 | ||
140 | 140 | ||
141 | def test_json2c(): | 141 | def test_json2c(): |