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.

208 lines
5.9 KiB

  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 time import strftime
  11. from milc import cli
  12. import qmk.keymap
  13. from qmk.constants import KEYBOARD_OUTPUT_PREFIX
  14. time_fmt = '%Y-%m-%d-%H:%M:%S'
  15. def _find_make():
  16. """Returns the correct make command for this environment.
  17. """
  18. make_cmd = os.environ.get('MAKE')
  19. if not make_cmd:
  20. make_cmd = 'gmake' if shutil.which('gmake') else 'make'
  21. return make_cmd
  22. def create_make_command(keyboard, keymap, target=None, parallel=1, **env_vars):
  23. """Create a make compile command
  24. Args:
  25. keyboard
  26. The path of the keyboard, for example 'plank'
  27. keymap
  28. The name of the keymap, for example 'algernon'
  29. target
  30. Usually a bootloader.
  31. parallel
  32. The number of make jobs to run in parallel
  33. **env_vars
  34. Environment variables to be passed to make.
  35. Returns:
  36. A command that can be run to make the specified keyboard and keymap
  37. """
  38. env = []
  39. make_args = [keyboard, keymap]
  40. make_cmd = _find_make()
  41. if target:
  42. make_args.append(target)
  43. for key, value in env_vars.items():
  44. env.append(f'{key}={value}')
  45. return [make_cmd, '-j', str(parallel), *env, ':'.join(make_args)]
  46. def get_git_version(repo_dir='.', check_dir='.'):
  47. """Returns the current git version for a repo, or the current time.
  48. """
  49. git_describe_cmd = ['git', 'describe', '--abbrev=6', '--dirty', '--always', '--tags']
  50. if Path(check_dir).exists():
  51. git_describe = cli.run(git_describe_cmd, cwd=repo_dir)
  52. if git_describe.returncode == 0:
  53. return git_describe.stdout.strip()
  54. else:
  55. cli.args.warn(f'"{" ".join(git_describe_cmd)}" returned error code {git_describe.returncode}')
  56. print(git_describe.stderr)
  57. return strftime(time_fmt)
  58. return strftime(time_fmt)
  59. def write_version_h(git_version, build_date, chibios_version, chibios_contrib_version):
  60. """Generate and write quantum/version.h
  61. """
  62. version_h = [
  63. f'#define QMK_VERSION "{git_version}"',
  64. f'#define QMK_BUILDDATE "{build_date}"',
  65. f'#define CHIBIOS_VERSION "{chibios_version}"',
  66. f'#define CHIBIOS_CONTRIB_VERSION "{chibios_contrib_version}"',
  67. ]
  68. version_h_file = Path('quantum/version.h')
  69. version_h_file.write_text('\n'.join(version_h))
  70. def compile_configurator_json(user_keymap, parallel=1, **env_vars):
  71. """Convert a configurator export JSON file into a C file and then compile it.
  72. Args:
  73. user_keymap
  74. A deserialized keymap export
  75. bootloader
  76. A bootloader to flash
  77. parallel
  78. The number of make jobs to run in parallel
  79. Returns:
  80. A command to run to compile and flash the C file.
  81. """
  82. # Write the keymap.c file
  83. keyboard_filesafe = user_keymap['keyboard'].replace('/', '_')
  84. target = f'{keyboard_filesafe}_{user_keymap["keymap"]}'
  85. keyboard_output = Path(f'{KEYBOARD_OUTPUT_PREFIX}{keyboard_filesafe}')
  86. keymap_output = Path(f'{keyboard_output}_{user_keymap["keymap"]}')
  87. c_text = qmk.keymap.generate_c(user_keymap['keyboard'], user_keymap['layout'], user_keymap['layers'])
  88. keymap_dir = keymap_output / 'src'
  89. keymap_c = keymap_dir / 'keymap.c'
  90. keymap_dir.mkdir(exist_ok=True, parents=True)
  91. keymap_c.write_text(c_text)
  92. # Write the version.h file
  93. git_version = get_git_version()
  94. build_date = strftime('%Y-%m-%d-%H:%M:%S')
  95. chibios_version = get_git_version("lib/chibios", "lib/chibios/os")
  96. chibios_contrib_version = get_git_version("lib/chibios-contrib", "lib/chibios-contrib/os")
  97. write_version_h(git_version, build_date, chibios_version, chibios_contrib_version)
  98. # Return a command that can be run to make the keymap and flash if given
  99. verbose = 'true' if cli.config.general.verbose else 'false'
  100. color = 'true' if cli.config.general.color else 'false'
  101. make_command = [_find_make()]
  102. if not cli.config.general.verbose:
  103. make_command.append('-s')
  104. make_command.extend([
  105. '-j',
  106. str(parallel),
  107. '-r',
  108. '-R',
  109. '-f',
  110. 'build_keyboard.mk',
  111. ])
  112. for key, value in env_vars.items():
  113. make_command.append(f'{key}={value}')
  114. make_command.extend([
  115. f'GIT_VERSION={git_version}',
  116. f'BUILD_DATE={build_date}',
  117. f'CHIBIOS_VERSION={chibios_version}',
  118. f'CHIBIOS_CONTRIB_VERSION={chibios_contrib_version}',
  119. f'KEYBOARD={user_keymap["keyboard"]}',
  120. f'KEYMAP={user_keymap["keymap"]}',
  121. f'KEYBOARD_FILESAFE={keyboard_filesafe}',
  122. f'TARGET={target}',
  123. f'KEYBOARD_OUTPUT={keyboard_output}',
  124. f'KEYMAP_OUTPUT={keymap_output}',
  125. f'MAIN_KEYMAP_PATH_1={keymap_output}',
  126. f'MAIN_KEYMAP_PATH_2={keymap_output}',
  127. f'MAIN_KEYMAP_PATH_3={keymap_output}',
  128. f'MAIN_KEYMAP_PATH_4={keymap_output}',
  129. f'MAIN_KEYMAP_PATH_5={keymap_output}',
  130. f'KEYMAP_C={keymap_c}',
  131. f'KEYMAP_PATH={keymap_dir}',
  132. f'VERBOSE={verbose}',
  133. f'COLOR={color}',
  134. 'SILENT=false',
  135. ])
  136. return make_command
  137. def parse_configurator_json(configurator_file):
  138. """Open and parse a configurator json export
  139. """
  140. # FIXME(skullydazed/anyone): Add validation here
  141. user_keymap = json.load(configurator_file)
  142. return user_keymap
  143. def run(command, *args, **kwargs):
  144. """Run a command with subprocess.run
  145. """
  146. platform_id = platform.platform().lower()
  147. if isinstance(command, str):
  148. raise TypeError('`command` must be a non-text sequence such as list or tuple.')
  149. if 'windows' in platform_id:
  150. safecmd = map(str, command)
  151. safecmd = map(shlex.quote, safecmd)
  152. safecmd = ' '.join(safecmd)
  153. command = [os.environ['SHELL'], '-c', safecmd]
  154. return subprocess.run(command, *args, **kwargs)