summaryrefslogtreecommitdiff
path: root/lib/python/qmk/cli/flash.py
diff options
context:
space:
mode:
authorErovia <Erovia@users.noreply.github.com>2022-08-20 06:39:19 +0100
committerGitHub <noreply@github.com>2022-08-20 15:39:19 +1000
commit5e2ffe7d8f4187109514147469d7db93e075f6f0 (patch)
tree83552a38351b50f6ab175c6abd6070abcc3d78a0 /lib/python/qmk/cli/flash.py
parent3bf36e8b04be5af9826fe3241d227efb185a4a31 (diff)
CLI: Teaching the CLI to flash binaries (#16584)
Co-authored-by: Ryan <fauxpark@gmail.com> Co-authored-by: Sergey Vlasov <sigprof@gmail.com> Co-authored-by: Joel Challis <git@zvecr.com> Co-authored-by: Nick Brassel <nick@tzarc.org>
Diffstat (limited to 'lib/python/qmk/cli/flash.py')
-rw-r--r--lib/python/qmk/cli/flash.py120
1 files changed, 69 insertions, 51 deletions
diff --git a/lib/python/qmk/cli/flash.py b/lib/python/qmk/cli/flash.py
index ebe739c50e..c39f4b36d4 100644
--- a/lib/python/qmk/cli/flash.py
+++ b/lib/python/qmk/cli/flash.py
@@ -4,6 +4,7 @@ You can compile a keymap already in the repo or using a QMK Configurator export.
4A bootloader must be specified. 4A bootloader must be specified.
5""" 5"""
6from subprocess import DEVNULL 6from subprocess import DEVNULL
7import sys
7 8
8from argcomplete.completers import FilesCompleter 9from argcomplete.completers import FilesCompleter
9from milc import cli 10from milc import cli
@@ -12,6 +13,7 @@ import qmk.path
12from qmk.decorators import automagic_keyboard, automagic_keymap 13from qmk.decorators import automagic_keyboard, automagic_keymap
13from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json 14from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
14from qmk.keyboard import keyboard_completer, keyboard_folder 15from qmk.keyboard import keyboard_completer, keyboard_folder
16from qmk.flashers import flasher
15 17
16 18
17def print_bootloader_help(): 19def print_bootloader_help():
@@ -38,9 +40,10 @@ def print_bootloader_help():
38 cli.echo('For more info, visit https://docs.qmk.fm/#/flashing') 40 cli.echo('For more info, visit https://docs.qmk.fm/#/flashing')
39 41
40 42
41@cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), completer=FilesCompleter('.json'), help='The configurator export JSON to compile.') 43@cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), completer=FilesCompleter('.json'), help='A configurator export JSON to be compiled and flashed or a pre-compiled binary firmware file (bin/hex) to be flashed.')
42@cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.') 44@cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.')
43@cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.') 45@cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.')
46@cli.argument('-m', '--mcu', help='The MCU name. Required for HalfKay, HID, USBAspLoader and ISP flashing.')
44@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.') 47@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.')
45@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.') 48@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
46@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.") 49@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
@@ -53,6 +56,8 @@ def print_bootloader_help():
53def flash(cli): 56def flash(cli):
54 """Compile and or flash QMK Firmware or keyboard/layout 57 """Compile and or flash QMK Firmware or keyboard/layout
55 58
59 If a binary firmware is supplied, try to flash that.
60
56 If a Configurator JSON export is supplied this command will create a new keymap. Keymap and Keyboard arguments 61 If a Configurator JSON export is supplied this command will create a new keymap. Keymap and Keyboard arguments
57 will be ignored. 62 will be ignored.
58 63
@@ -60,56 +65,69 @@ def flash(cli):
60 65
61 If bootloader is omitted the make system will use the configured bootloader for that keyboard. 66 If bootloader is omitted the make system will use the configured bootloader for that keyboard.
62 """ 67 """
63 if cli.args.clean and not cli.args.filename and not cli.args.dry_run: 68 if cli.args.filename and cli.args.filename.suffix in ['.bin', '.hex']:
64 if cli.config.flash.keyboard and cli.config.flash.keymap: 69 # Try to flash binary firmware
65 command = create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, 'clean') 70 cli.echo('Flashing binary firmware...\nPlease reset your keyboard into bootloader mode now!\nPress Ctrl-C to exit.\n')
66 cli.run(command, capture_output=False, stdin=DEVNULL) 71 try:
67 72 err, msg = flasher(cli.args.mcu, cli.args.filename)
68 # Build the environment vars 73 if err:
69 envs = {} 74 cli.log.error(msg)
70 for env in cli.args.env: 75 return False
71 if '=' in env: 76 except KeyboardInterrupt:
72 key, value = env.split('=', 1) 77 cli.log.info('Ctrl-C was pressed, exiting...')
73 envs[key] = value 78 sys.exit(0)
74 else:
75 cli.log.warning('Invalid environment variable: %s', env)
76
77 # Determine the compile command
78 command = ''
79
80 if cli.args.bootloaders:
81 # Provide usage and list bootloaders
82 cli.echo('usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename]')
83 print_bootloader_help()
84 return False
85
86 if cli.args.filename:
87 # Handle compiling a configurator JSON
88 user_keymap = parse_configurator_json(cli.args.filename)
89 keymap_path = qmk.path.keymap(user_keymap['keyboard'])
90 command = compile_configurator_json(user_keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, **envs)
91
92 cli.log.info('Wrote keymap to {fg_cyan}%s/%s/keymap.c', keymap_path, user_keymap['keymap'])
93 79
94 else: 80 else:
95 if cli.config.flash.keyboard and cli.config.flash.keymap: 81 if cli.args.clean and not cli.args.filename and not cli.args.dry_run:
96 # Generate the make command for a specific keyboard/keymap. 82 if cli.config.flash.keyboard and cli.config.flash.keymap:
97 command = create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, **envs) 83 command = create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, 'clean')
98 84 cli.run(command, capture_output=False, stdin=DEVNULL)
99 elif not cli.config.flash.keyboard: 85
100 cli.log.error('Could not determine keyboard!') 86 # Build the environment vars
101 elif not cli.config.flash.keymap: 87 envs = {}
102 cli.log.error('Could not determine keymap!') 88 for env in cli.args.env:
103 89 if '=' in env:
104 # Compile the firmware, if we're able to 90 key, value = env.split('=', 1)
105 if command: 91 envs[key] = value
106 cli.log.info('Compiling keymap with {fg_cyan}%s', ' '.join(command)) 92 else:
107 if not cli.args.dry_run: 93 cli.log.warning('Invalid environment variable: %s', env)
108 cli.echo('\n') 94
109 compile = cli.run(command, capture_output=False, stdin=DEVNULL) 95 # Determine the compile command
110 return compile.returncode 96 command = ''
97
98 if cli.args.bootloaders:
99 # Provide usage and list bootloaders
100 cli.echo('usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename]')
101 print_bootloader_help()
102 return False
103
104 if cli.args.filename:
105 # Handle compiling a configurator JSON
106 user_keymap = parse_configurator_json(cli.args.filename)
107 keymap_path = qmk.path.keymap(user_keymap['keyboard'])
108 command = compile_configurator_json(user_keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, **envs)
109
110 cli.log.info('Wrote keymap to {fg_cyan}%s/%s/keymap.c', keymap_path, user_keymap['keymap'])
111 111
112 else: 112 else:
113 cli.log.error('You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.') 113 if cli.config.flash.keyboard and cli.config.flash.keymap:
114 cli.echo('usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename]') 114 # Generate the make command for a specific keyboard/keymap.
115 return False 115 command = create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, **envs)
116
117 elif not cli.config.flash.keyboard:
118 cli.log.error('Could not determine keyboard!')
119 elif not cli.config.flash.keymap:
120 cli.log.error('Could not determine keymap!')
121
122 # Compile the firmware, if we're able to
123 if command:
124 cli.log.info('Compiling keymap with {fg_cyan}%s', ' '.join(command))
125 if not cli.args.dry_run:
126 cli.echo('\n')
127 compile = cli.run(command, capture_output=False, stdin=DEVNULL)
128 return compile.returncode
129
130 else:
131 cli.log.error('You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.')
132 cli.echo('usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename]')
133 return False