2019-10-05 12:38:34 +06:00
""" Compile and flash QMK Firmware
You can compile a keymap already in the repo or using a QMK Configurator export .
A bootloader must be specified .
"""
2019-11-21 04:54:18 +06:00
from milc import cli
2020-03-14 04:47:04 +06:00
import qmk . path
from qmk . decorators import automagic_keyboard , automagic_keymap
from qmk . commands import compile_configurator_json , create_make_command , parse_configurator_json
2021-03-24 22:26:38 +06:00
from qmk . keyboard import keyboard_folder
2019-10-05 12:38:34 +06:00
def print_bootloader_help ( ) :
""" Prints the available bootloaders listed in docs.qmk.fm.
"""
cli . log . info ( ' Here are the available bootloaders: ' )
cli . echo ( ' \t dfu ' )
cli . echo ( ' \t dfu-ee ' )
cli . echo ( ' \t dfu-split-left ' )
cli . echo ( ' \t dfu-split-right ' )
cli . echo ( ' \t avrdude ' )
cli . echo ( ' \t BootloadHID ' )
cli . echo ( ' \t dfu-util ' )
cli . echo ( ' \t dfu-util-split-left ' )
cli . echo ( ' \t dfu-util-split-right ' )
cli . echo ( ' \t st-link-cli ' )
2020-08-12 21:53:53 +06:00
cli . echo ( ' \t st-flash ' )
2019-10-05 12:38:34 +06:00
cli . echo ( ' For more info, visit https://docs.qmk.fm/#/flashing ' )
2019-11-16 13:10:19 +06:00
2021-02-08 03:02:51 +06:00
@cli.argument ( ' filename ' , nargs = ' ? ' , arg_only = True , type = qmk . path . FileType ( ' r ' ) , help = ' The configurator export JSON to compile. ' )
2020-03-14 04:47:04 +06:00
@cli.argument ( ' -b ' , ' --bootloaders ' , action = ' store_true ' , help = ' List the available bootloaders. ' )
@cli.argument ( ' -bl ' , ' --bootloader ' , default = ' flash ' , help = ' The flash command, corresponding to qmk \' s make options of bootloaders. ' )
2019-10-05 12:38:34 +06:00
@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. ' )
2021-03-24 22:26:38 +06:00
@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. ' )
2020-03-14 04:47:04 +06:00
@cli.argument ( ' -n ' , ' --dry-run ' , arg_only = True , action = ' store_true ' , help = " Don ' t actually build, just show the make command to be run. " )
2021-01-17 05:13:04 +06:00
@cli.argument ( ' -j ' , ' --parallel ' , type = int , default = 1 , help = " Set the number of parallel make jobs to run. " )
@cli.argument ( ' -e ' , ' --env ' , arg_only = True , action = ' append ' , default = [ ] , help = " Set a variable to be passed to make. May be passed multiple times. " )
@cli.argument ( ' -c ' , ' --clean ' , arg_only = True , action = ' store_true ' , help = " Remove object files before compiling. " )
2019-10-05 12:38:34 +06:00
@cli.subcommand ( ' QMK Flash. ' )
2020-03-14 04:47:04 +06:00
@automagic_keyboard
@automagic_keymap
2019-10-05 12:38:34 +06:00
def flash ( cli ) :
""" Compile and or flash QMK Firmware or keyboard/layout
If a Configurator JSON export is supplied this command will create a new keymap . Keymap and Keyboard arguments
will be ignored .
If no file is supplied , keymap and keyboard are expected .
2020-03-14 04:47:04 +06:00
If bootloader is omitted the make system will use the configured bootloader for that keyboard .
2019-10-05 12:38:34 +06:00
"""
2021-01-17 05:13:04 +06:00
if cli . args . clean and not cli . args . filename and not cli . args . dry_run :
command = create_make_command ( cli . config . flash . keyboard , cli . config . flash . keymap , ' clean ' )
cli . run ( command , capture_output = False )
# Build the environment vars
envs = { }
for env in cli . args . env :
if ' = ' in env :
key , value = env . split ( ' = ' , 1 )
envs [ key ] = value
else :
cli . log . warning ( ' Invalid environment variable: %s ' , env )
# Determine the compile command
2020-03-14 04:47:04 +06:00
command = ' '
2019-10-05 12:38:34 +06:00
if cli . args . bootloaders :
# Provide usage and list bootloaders
2020-03-14 04:47:04 +06:00
cli . echo ( ' usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename] ' )
2019-10-05 12:38:34 +06:00
print_bootloader_help ( )
return False
2020-02-18 01:42:11 +06:00
if cli . args . filename :
# Handle compiling a configurator JSON
2021-02-02 01:55:35 +06:00
user_keymap = parse_configurator_json ( cli . args . filename )
2019-10-05 12:38:34 +06:00
keymap_path = qmk . path . keymap ( user_keymap [ ' keyboard ' ] )
2021-02-02 01:55:35 +06:00
command = compile_configurator_json ( user_keymap , cli . args . bootloader , parallel = cli . config . flash . parallel , * * envs )
2019-10-05 12:38:34 +06:00
cli . log . info ( ' Wrote keymap to {fg_cyan} %s / %s /keymap.c ' , keymap_path , user_keymap [ ' keymap ' ] )
else :
2020-03-14 04:47:04 +06:00
if cli . config . flash . keyboard and cli . config . flash . keymap :
2020-02-18 01:42:11 +06:00
# Generate the make command for a specific keyboard/keymap.
2021-01-17 05:13:04 +06:00
command = create_make_command ( cli . config . flash . keyboard , cli . config . flash . keymap , cli . args . bootloader , parallel = cli . config . flash . parallel , * * envs )
2020-02-18 01:42:11 +06:00
2020-03-14 04:47:04 +06:00
elif not cli . config . flash . keyboard :
cli . log . error ( ' Could not determine keyboard! ' )
elif not cli . config . flash . keymap :
cli . log . error ( ' Could not determine keymap! ' )
2019-10-05 12:38:34 +06:00
2020-03-14 04:47:04 +06:00
# Compile the firmware, if we're able to
if command :
cli . log . info ( ' Compiling keymap with {fg_cyan} %s ' , ' ' . join ( command ) )
if not cli . args . dry_run :
cli . echo ( ' \n ' )
2021-01-17 05:13:04 +06:00
compile = cli . run ( command , capture_output = False , text = True )
2021-01-02 23:27:35 +06:00
return compile . returncode
2020-03-14 04:47:04 +06:00
else :
cli . log . error ( ' You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap. ' )
cli . echo ( ' usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename] ' )
return False