diff options
| -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 6a57c1ff5..d742f6756 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 | ||
| @@ -190,6 +191,15 @@ def parse_configurator_json(configurator_file): | |||
| 190 | """ | 191 | """ |
| 191 | # FIXME(skullydazed/anyone): Add validation here | 192 | # FIXME(skullydazed/anyone): Add validation here |
| 192 | user_keymap = json.load(configurator_file) | 193 | user_keymap = json.load(configurator_file) |
| 194 | orig_keyboard = user_keymap['keyboard'] | ||
| 195 | aliases = json_load(Path('data/mappings/keyboard_aliases.json')) | ||
| 196 | |||
| 197 | if orig_keyboard in aliases: | ||
| 198 | if 'target' in aliases[orig_keyboard]: | ||
| 199 | user_keymap['keyboard'] = aliases[orig_keyboard]['target'] | ||
| 200 | |||
| 201 | if 'layouts' in aliases[orig_keyboard] and user_keymap['layout'] in aliases[orig_keyboard]['layouts']: | ||
| 202 | user_keymap['layout'] = aliases[orig_keyboard]['layouts'][user_keymap['layout']] | ||
| 193 | 203 | ||
| 194 | return user_keymap | 204 | return user_keymap |
| 195 | 205 | ||
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 82c42a20e..a97472e6b 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(): |
