You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
5.0 KiB

  1. """Compile and flash QMK Firmware
  2. You can compile a keymap already in the repo or using a QMK Configurator export.
  3. A bootloader must be specified.
  4. """
  5. from subprocess import DEVNULL
  6. from argcomplete.completers import FilesCompleter
  7. from milc import cli
  8. import qmk.path
  9. from qmk.decorators import automagic_keyboard, automagic_keymap
  10. from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
  11. from qmk.keyboard import keyboard_completer, is_keyboard_target
  12. def print_bootloader_help():
  13. """Prints the available bootloaders listed in docs.qmk.fm.
  14. """
  15. cli.log.info('Here are the available bootloaders:')
  16. cli.echo('\tdfu')
  17. cli.echo('\tdfu-ee')
  18. cli.echo('\tdfu-split-left')
  19. cli.echo('\tdfu-split-right')
  20. cli.echo('\tavrdude')
  21. cli.echo('\tBootloadHID')
  22. cli.echo('\tdfu-util')
  23. cli.echo('\tdfu-util-split-left')
  24. cli.echo('\tdfu-util-split-right')
  25. cli.echo('\tst-link-cli')
  26. cli.echo('\tst-flash')
  27. cli.echo('For more info, visit https://docs.qmk.fm/#/flashing')
  28. @cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), completer=FilesCompleter('.json'), help='The configurator export JSON to compile.')
  29. @cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.')
  30. @cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.')
  31. @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.')
  32. @cli.argument('-kb', '--keyboard', type=is_keyboard_target, 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.')
  33. @cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
  34. @cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.")
  35. @cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.")
  36. @cli.argument('-c', '--clean', arg_only=True, action='store_true', help="Remove object files before compiling.")
  37. @cli.subcommand('QMK Flash.')
  38. @automagic_keyboard
  39. @automagic_keymap
  40. def flash(cli):
  41. """Compile and or flash QMK Firmware or keyboard/layout
  42. If a Configurator JSON export is supplied this command will create a new keymap. Keymap and Keyboard arguments
  43. will be ignored.
  44. If no file is supplied, keymap and keyboard are expected.
  45. If bootloader is omitted the make system will use the configured bootloader for that keyboard.
  46. """
  47. if cli.args.clean and not cli.args.filename and not cli.args.dry_run:
  48. command = create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, 'clean')
  49. cli.run(command, capture_output=False, stdin=DEVNULL)
  50. # Build the environment vars
  51. envs = {}
  52. for env in cli.args.env:
  53. if '=' in env:
  54. key, value = env.split('=', 1)
  55. envs[key] = value
  56. else:
  57. cli.log.warning('Invalid environment variable: %s', env)
  58. # Determine the compile command
  59. command = ''
  60. if cli.args.bootloaders:
  61. # Provide usage and list bootloaders
  62. cli.echo('usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename]')
  63. print_bootloader_help()
  64. return False
  65. if cli.args.filename:
  66. # Handle compiling a configurator JSON
  67. user_keymap = parse_configurator_json(cli.args.filename)
  68. keymap_path = qmk.path.keymap(user_keymap['keyboard'])
  69. command = compile_configurator_json(user_keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, **envs)
  70. cli.log.info('Wrote keymap to {fg_cyan}%s/%s/keymap.c', keymap_path, user_keymap['keymap'])
  71. else:
  72. if cli.config.flash.keyboard and cli.config.flash.keymap:
  73. # Generate the make command for a specific keyboard/keymap.
  74. command = create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, **envs)
  75. elif not cli.config.flash.keyboard:
  76. cli.log.error('Could not determine keyboard!')
  77. elif not cli.config.flash.keymap:
  78. cli.log.error('Could not determine keymap!')
  79. # Compile the firmware, if we're able to
  80. if command:
  81. cli.log.info('Compiling keymap with {fg_cyan}%s', ' '.join(command))
  82. if not cli.args.dry_run:
  83. cli.echo('\n')
  84. compile = cli.run(command, capture_output=False, stdin=DEVNULL)
  85. return compile.returncode
  86. else:
  87. cli.log.error('You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.')
  88. cli.echo('usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename]')
  89. return False