commands.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. """Helper functions for commands.
  2. """
  3. import json
  4. import os
  5. import platform
  6. import subprocess
  7. import shlex
  8. import shutil
  9. from pathlib import Path
  10. from milc import cli
  11. import qmk.keymap
  12. from qmk.constants import KEYBOARD_OUTPUT_PREFIX
  13. def _find_make():
  14. """Returns the correct make command for this environment.
  15. """
  16. make_cmd = os.environ.get('MAKE')
  17. if not make_cmd:
  18. make_cmd = 'gmake' if shutil.which('gmake') else 'make'
  19. return make_cmd
  20. def create_make_command(keyboard, keymap, target=None, parallel=1, **env_vars):
  21. """Create a make compile command
  22. Args:
  23. keyboard
  24. The path of the keyboard, for example 'plank'
  25. keymap
  26. The name of the keymap, for example 'algernon'
  27. target
  28. Usually a bootloader.
  29. parallel
  30. The number of make jobs to run in parallel
  31. **env_vars
  32. Environment variables to be passed to make.
  33. Returns:
  34. A command that can be run to make the specified keyboard and keymap
  35. """
  36. env = []
  37. make_args = [keyboard, keymap]
  38. make_cmd = _find_make()
  39. if target:
  40. make_args.append(target)
  41. for key, value in env_vars.items():
  42. env.append(f'{key}={value}')
  43. return [make_cmd, '-j', str(parallel), *env, ':'.join(make_args)]
  44. def compile_configurator_json(user_keymap, parallel=1, **env_vars):
  45. """Convert a configurator export JSON file into a C file and then compile it.
  46. Args:
  47. user_keymap
  48. A deserialized keymap export
  49. bootloader
  50. A bootloader to flash
  51. parallel
  52. The number of make jobs to run in parallel
  53. Returns:
  54. A command to run to compile and flash the C file.
  55. """
  56. # Write the keymap.c file
  57. keyboard_filesafe = user_keymap['keyboard'].replace('/', '_')
  58. target = f'{keyboard_filesafe}_{user_keymap["keymap"]}'
  59. keyboard_output = Path(f'{KEYBOARD_OUTPUT_PREFIX}{keyboard_filesafe}')
  60. keymap_output = Path(f'{keyboard_output}_{user_keymap["keymap"]}')
  61. c_text = qmk.keymap.generate_c(user_keymap['keyboard'], user_keymap['layout'], user_keymap['layers'])
  62. keymap_dir = keymap_output / 'src'
  63. keymap_c = keymap_dir / 'keymap.c'
  64. keymap_dir.mkdir(exist_ok=True, parents=True)
  65. keymap_c.write_text(c_text)
  66. # Return a command that can be run to make the keymap and flash if given
  67. verbose = 'true' if cli.config.general.verbose else 'false'
  68. color = 'true' if cli.config.general.color else 'false'
  69. make_command = [
  70. _find_make(),
  71. '-j',
  72. str(parallel),
  73. '-r',
  74. '-R',
  75. '-f',
  76. 'build_keyboard.mk',
  77. ]
  78. for key, value in env_vars.items():
  79. make_command.append(f'{key}={value}')
  80. make_command.extend([
  81. f'KEYBOARD={user_keymap["keyboard"]}',
  82. f'KEYMAP={user_keymap["keymap"]}',
  83. f'KEYBOARD_FILESAFE={keyboard_filesafe}',
  84. f'TARGET={target}',
  85. f'KEYBOARD_OUTPUT={keyboard_output}',
  86. f'KEYMAP_OUTPUT={keymap_output}',
  87. f'MAIN_KEYMAP_PATH_1={keymap_output}',
  88. f'MAIN_KEYMAP_PATH_2={keymap_output}',
  89. f'MAIN_KEYMAP_PATH_3={keymap_output}',
  90. f'MAIN_KEYMAP_PATH_4={keymap_output}',
  91. f'MAIN_KEYMAP_PATH_5={keymap_output}',
  92. f'KEYMAP_C={keymap_c}',
  93. f'KEYMAP_PATH={keymap_dir}',
  94. f'VERBOSE={verbose}',
  95. f'COLOR={color}',
  96. 'SILENT=false',
  97. ])
  98. return make_command
  99. def parse_configurator_json(configurator_file):
  100. """Open and parse a configurator json export
  101. """
  102. # FIXME(skullydazed/anyone): Add validation here
  103. user_keymap = json.load(configurator_file)
  104. return user_keymap
  105. def run(command, *args, **kwargs):
  106. """Run a command with subprocess.run
  107. """
  108. platform_id = platform.platform().lower()
  109. if isinstance(command, str):
  110. raise TypeError('`command` must be a non-text sequence such as list or tuple.')
  111. if 'windows' in platform_id:
  112. safecmd = map(str, command)
  113. safecmd = map(shlex.quote, safecmd)
  114. safecmd = ' '.join(safecmd)
  115. command = [os.environ['SHELL'], '-c', safecmd]
  116. return subprocess.run(command, *args, **kwargs)