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.

340 lines
9.6 KiB

New CLI subcommand to create clang-compatible compilation database (`compile_commands.json`) (#14370) * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * remove MAKEFLAGS from environment for better control over process management * Update .gitignore Co-authored-by: Michael Forster <forster@google.com> * add a usage line to docs * doc change as suggested Co-authored-by: Nick Brassel <nick@tzarc.org> * rename command * remove debug print statements * generate-compilation-database: fix arg handling * generate-comilation-db: improve error handling * use cli.run() instead of Popen() Co-authored-by: Xton <cdewan@apple.com> Co-authored-by: Christon DeWan <cmdpix@mac.com> Co-authored-by: Michael Forster <forster@google.com> Co-authored-by: Nick Brassel <nick@tzarc.org>
2 years ago
New CLI subcommand to create clang-compatible compilation database (`compile_commands.json`) (#14370) * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * remove MAKEFLAGS from environment for better control over process management * Update .gitignore Co-authored-by: Michael Forster <forster@google.com> * add a usage line to docs * doc change as suggested Co-authored-by: Nick Brassel <nick@tzarc.org> * rename command * remove debug print statements * generate-compilation-database: fix arg handling * generate-comilation-db: improve error handling * use cli.run() instead of Popen() Co-authored-by: Xton <cdewan@apple.com> Co-authored-by: Christon DeWan <cmdpix@mac.com> Co-authored-by: Michael Forster <forster@google.com> Co-authored-by: Nick Brassel <nick@tzarc.org>
2 years ago
New CLI subcommand to create clang-compatible compilation database (`compile_commands.json`) (#14370) * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * remove MAKEFLAGS from environment for better control over process management * Update .gitignore Co-authored-by: Michael Forster <forster@google.com> * add a usage line to docs * doc change as suggested Co-authored-by: Nick Brassel <nick@tzarc.org> * rename command * remove debug print statements * generate-compilation-database: fix arg handling * generate-comilation-db: improve error handling * use cli.run() instead of Popen() Co-authored-by: Xton <cdewan@apple.com> Co-authored-by: Christon DeWan <cmdpix@mac.com> Co-authored-by: Michael Forster <forster@google.com> Co-authored-by: Nick Brassel <nick@tzarc.org>
2 years ago
New CLI subcommand to create clang-compatible compilation database (`compile_commands.json`) (#14370) * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * remove MAKEFLAGS from environment for better control over process management * Update .gitignore Co-authored-by: Michael Forster <forster@google.com> * add a usage line to docs * doc change as suggested Co-authored-by: Nick Brassel <nick@tzarc.org> * rename command * remove debug print statements * generate-compilation-database: fix arg handling * generate-comilation-db: improve error handling * use cli.run() instead of Popen() Co-authored-by: Xton <cdewan@apple.com> Co-authored-by: Christon DeWan <cmdpix@mac.com> Co-authored-by: Michael Forster <forster@google.com> Co-authored-by: Nick Brassel <nick@tzarc.org>
2 years ago
New CLI subcommand to create clang-compatible compilation database (`compile_commands.json`) (#14370) * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * remove MAKEFLAGS from environment for better control over process management * Update .gitignore Co-authored-by: Michael Forster <forster@google.com> * add a usage line to docs * doc change as suggested Co-authored-by: Nick Brassel <nick@tzarc.org> * rename command * remove debug print statements * generate-compilation-database: fix arg handling * generate-comilation-db: improve error handling * use cli.run() instead of Popen() Co-authored-by: Xton <cdewan@apple.com> Co-authored-by: Christon DeWan <cmdpix@mac.com> Co-authored-by: Michael Forster <forster@google.com> Co-authored-by: Nick Brassel <nick@tzarc.org>
2 years ago
New CLI subcommand to create clang-compatible compilation database (`compile_commands.json`) (#14370) * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * pulled source from dev branch * missed a file from origin * formatting * revised argument names. relaxed matching rules to work for avr too * add docstrings * added docs. tightened up regex * remove unused imports * cleaning up command file. use existing qmk dir constant * rename parser library file * move lib functions into command file. there are only 2 and they aren't large * currently debugging... * more robustly find config * updated docs * remove unused imports * reuse make executable from the main make command * remove MAKEFLAGS from environment for better control over process management * Update .gitignore Co-authored-by: Michael Forster <forster@google.com> * add a usage line to docs * doc change as suggested Co-authored-by: Nick Brassel <nick@tzarc.org> * rename command * remove debug print statements * generate-compilation-database: fix arg handling * generate-comilation-db: improve error handling * use cli.run() instead of Popen() Co-authored-by: Xton <cdewan@apple.com> Co-authored-by: Christon DeWan <cmdpix@mac.com> Co-authored-by: Michael Forster <forster@google.com> Co-authored-by: Nick Brassel <nick@tzarc.org>
2 years ago
  1. """Helper functions for commands.
  2. """
  3. import json
  4. import os
  5. import sys
  6. import shutil
  7. from pathlib import Path
  8. from subprocess import DEVNULL
  9. from time import strftime
  10. from milc import cli
  11. import qmk.keymap
  12. from qmk.constants import QMK_FIRMWARE, KEYBOARD_OUTPUT_PREFIX
  13. from qmk.json_schema import json_load
  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_target(target, dry_run=False, parallel=1, **env_vars):
  23. """Create a make command
  24. Args:
  25. target
  26. Usually a make rule, such as 'clean' or 'all'.
  27. dry_run
  28. make -n -- don't actually build
  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_cmd = _find_make()
  38. for key, value in env_vars.items():
  39. env.append(f'{key}={value}')
  40. return [make_cmd, *(['-n'] if dry_run else []), *get_make_parallel_args(parallel), *env, target]
  41. def create_make_command(keyboard, keymap, target=None, dry_run=False, parallel=1, **env_vars):
  42. """Create a make compile command
  43. Args:
  44. keyboard
  45. The path of the keyboard, for example 'plank'
  46. keymap
  47. The name of the keymap, for example 'algernon'
  48. target
  49. Usually a bootloader.
  50. dry_run
  51. make -n -- don't actually build
  52. parallel
  53. The number of make jobs to run in parallel
  54. **env_vars
  55. Environment variables to be passed to make.
  56. Returns:
  57. A command that can be run to make the specified keyboard and keymap
  58. """
  59. make_args = [keyboard, keymap]
  60. if target:
  61. make_args.append(target)
  62. return create_make_target(':'.join(make_args), dry_run=dry_run, parallel=parallel, **env_vars)
  63. def get_git_version(current_time, repo_dir='.', check_dir='.'):
  64. """Returns the current git version for a repo, or the current time.
  65. """
  66. git_describe_cmd = ['git', 'describe', '--abbrev=6', '--dirty', '--always', '--tags']
  67. if repo_dir != '.':
  68. repo_dir = Path('lib') / repo_dir
  69. if check_dir != '.':
  70. check_dir = repo_dir / check_dir
  71. if Path(check_dir).exists():
  72. git_describe = cli.run(git_describe_cmd, stdin=DEVNULL, cwd=repo_dir)
  73. if git_describe.returncode == 0:
  74. return git_describe.stdout.strip()
  75. else:
  76. cli.log.warn(f'"{" ".join(git_describe_cmd)}" returned error code {git_describe.returncode}')
  77. print(git_describe.stderr)
  78. return current_time
  79. return current_time
  80. def get_make_parallel_args(parallel=1):
  81. """Returns the arguments for running the specified number of parallel jobs.
  82. """
  83. parallel_args = []
  84. if int(parallel) <= 0:
  85. # 0 or -1 means -j without argument (unlimited jobs)
  86. parallel_args.append('--jobs')
  87. else:
  88. parallel_args.append('--jobs=' + str(parallel))
  89. if int(parallel) != 1:
  90. # If more than 1 job is used, synchronize parallel output by target
  91. parallel_args.append('--output-sync=target')
  92. return parallel_args
  93. def create_version_h(skip_git=False, skip_all=False):
  94. """Generate version.h contents
  95. """
  96. if skip_all:
  97. current_time = "1970-01-01-00:00:00"
  98. else:
  99. current_time = strftime(time_fmt)
  100. if skip_git:
  101. git_version = "NA"
  102. chibios_version = "NA"
  103. chibios_contrib_version = "NA"
  104. else:
  105. git_version = get_git_version(current_time)
  106. chibios_version = get_git_version(current_time, "chibios", "os")
  107. chibios_contrib_version = get_git_version(current_time, "chibios-contrib", "os")
  108. version_h_lines = f"""/* This file was automatically generated. Do not edit or copy.
  109. */
  110. #pragma once
  111. #define QMK_VERSION "{git_version}"
  112. #define QMK_BUILDDATE "{current_time}"
  113. #define CHIBIOS_VERSION "{chibios_version}"
  114. #define CHIBIOS_CONTRIB_VERSION "{chibios_contrib_version}"
  115. """
  116. return version_h_lines
  117. def compile_configurator_json(user_keymap, bootloader=None, parallel=1, **env_vars):
  118. """Convert a configurator export JSON file into a C file and then compile it.
  119. Args:
  120. user_keymap
  121. A deserialized keymap export
  122. bootloader
  123. A bootloader to flash
  124. parallel
  125. The number of make jobs to run in parallel
  126. Returns:
  127. A command to run to compile and flash the C file.
  128. """
  129. # Write the keymap.c file
  130. keyboard_filesafe = user_keymap['keyboard'].replace('/', '_')
  131. target = f'{keyboard_filesafe}_{user_keymap["keymap"]}'
  132. keyboard_output = Path(f'{KEYBOARD_OUTPUT_PREFIX}{keyboard_filesafe}')
  133. keymap_output = Path(f'{keyboard_output}_{user_keymap["keymap"]}')
  134. c_text = qmk.keymap.generate_c(user_keymap)
  135. keymap_dir = keymap_output / 'src'
  136. keymap_c = keymap_dir / 'keymap.c'
  137. keymap_dir.mkdir(exist_ok=True, parents=True)
  138. keymap_c.write_text(c_text)
  139. version_h = Path('quantum/version.h')
  140. version_h.write_text(create_version_h())
  141. # Return a command that can be run to make the keymap and flash if given
  142. verbose = 'true' if cli.config.general.verbose else 'false'
  143. color = 'true' if cli.config.general.color else 'false'
  144. make_command = [_find_make()]
  145. if not cli.config.general.verbose:
  146. make_command.append('-s')
  147. make_command.extend([
  148. *get_make_parallel_args(parallel),
  149. '-r',
  150. '-R',
  151. '-f',
  152. 'build_keyboard.mk',
  153. ])
  154. if bootloader:
  155. make_command.append(bootloader)
  156. for key, value in env_vars.items():
  157. make_command.append(f'{key}={value}')
  158. make_command.extend([
  159. f'KEYBOARD={user_keymap["keyboard"]}',
  160. f'KEYMAP={user_keymap["keymap"]}',
  161. f'KEYBOARD_FILESAFE={keyboard_filesafe}',
  162. f'TARGET={target}',
  163. f'KEYBOARD_OUTPUT={keyboard_output}',
  164. f'KEYMAP_OUTPUT={keymap_output}',
  165. f'MAIN_KEYMAP_PATH_1={keymap_output}',
  166. f'MAIN_KEYMAP_PATH_2={keymap_output}',
  167. f'MAIN_KEYMAP_PATH_3={keymap_output}',
  168. f'MAIN_KEYMAP_PATH_4={keymap_output}',
  169. f'MAIN_KEYMAP_PATH_5={keymap_output}',
  170. f'KEYMAP_C={keymap_c}',
  171. f'KEYMAP_PATH={keymap_dir}',
  172. f'VERBOSE={verbose}',
  173. f'COLOR={color}',
  174. 'SILENT=false',
  175. 'QMK_BIN="qmk"',
  176. ])
  177. return make_command
  178. def parse_configurator_json(configurator_file):
  179. """Open and parse a configurator json export
  180. """
  181. # FIXME(skullydazed/anyone): Add validation here
  182. user_keymap = json.load(configurator_file)
  183. orig_keyboard = user_keymap['keyboard']
  184. aliases = json_load(Path('data/mappings/keyboard_aliases.json'))
  185. if orig_keyboard in aliases:
  186. if 'target' in aliases[orig_keyboard]:
  187. user_keymap['keyboard'] = aliases[orig_keyboard]['target']
  188. if 'layouts' in aliases[orig_keyboard] and user_keymap['layout'] in aliases[orig_keyboard]['layouts']:
  189. user_keymap['layout'] = aliases[orig_keyboard]['layouts'][user_keymap['layout']]
  190. return user_keymap
  191. def git_get_username():
  192. """Retrieves user's username from Git config, if set.
  193. """
  194. git_username = cli.run(['git', 'config', '--get', 'user.name'])
  195. if git_username.returncode == 0 and git_username.stdout:
  196. return git_username.stdout.strip()
  197. def git_check_repo():
  198. """Checks that the .git directory exists inside QMK_HOME.
  199. This is a decent enough indicator that the qmk_firmware directory is a
  200. proper Git repository, rather than a .zip download from GitHub.
  201. """
  202. dot_git_dir = QMK_FIRMWARE / '.git'
  203. return dot_git_dir.is_dir()
  204. def git_get_branch():
  205. """Returns the current branch for a repo, or None.
  206. """
  207. git_branch = cli.run(['git', 'branch', '--show-current'])
  208. if not git_branch.returncode != 0 or not git_branch.stdout:
  209. # Workaround for Git pre-2.22
  210. git_branch = cli.run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
  211. if git_branch.returncode == 0:
  212. return git_branch.stdout.strip()
  213. def git_is_dirty():
  214. """Returns 1 if repo is dirty, or 0 if clean
  215. """
  216. git_diff_staged_cmd = ['git', 'diff', '--quiet']
  217. git_diff_unstaged_cmd = [*git_diff_staged_cmd, '--cached']
  218. unstaged = cli.run(git_diff_staged_cmd)
  219. staged = cli.run(git_diff_unstaged_cmd)
  220. return unstaged.returncode != 0 or staged.returncode != 0
  221. def git_get_remotes():
  222. """Returns the current remotes for a repo.
  223. """
  224. remotes = {}
  225. git_remote_show_cmd = ['git', 'remote', 'show']
  226. git_remote_get_cmd = ['git', 'remote', 'get-url']
  227. git_remote_show = cli.run(git_remote_show_cmd)
  228. if git_remote_show.returncode == 0:
  229. for name in git_remote_show.stdout.splitlines():
  230. git_remote_name = cli.run([*git_remote_get_cmd, name])
  231. remotes[name.strip()] = {"url": git_remote_name.stdout.strip()}
  232. return remotes
  233. def git_check_deviation(active_branch):
  234. """Return True if branch has custom commits
  235. """
  236. cli.run(['git', 'fetch', 'upstream', active_branch])
  237. deviations = cli.run(['git', '--no-pager', 'log', f'upstream/{active_branch}...{active_branch}'])
  238. return bool(deviations.returncode)
  239. def in_virtualenv():
  240. """Check if running inside a virtualenv.
  241. Based on https://stackoverflow.com/a/1883251
  242. """
  243. active_prefix = getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix
  244. return active_prefix != sys.prefix