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.

263 lines
7.4 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 os
  4. import sys
  5. import json
  6. import shutil
  7. from pathlib import Path
  8. from milc import cli
  9. import jsonschema
  10. from qmk.constants import INTERMEDIATE_OUTPUT_PREFIX
  11. from qmk.json_schema import json_load, validate
  12. def _find_make():
  13. """Returns the correct make command for this environment.
  14. """
  15. make_cmd = os.environ.get('MAKE')
  16. if not make_cmd:
  17. make_cmd = 'gmake' if shutil.which('gmake') else 'make'
  18. return make_cmd
  19. def create_make_target(target, dry_run=False, parallel=1, **env_vars):
  20. """Create a make command
  21. Args:
  22. target
  23. Usually a make rule, such as 'clean' or 'all'.
  24. dry_run
  25. make -n -- don't actually build
  26. parallel
  27. The number of make jobs to run in parallel
  28. **env_vars
  29. Environment variables to be passed to make.
  30. Returns:
  31. A command that can be run to make the specified keyboard and keymap
  32. """
  33. env = []
  34. make_cmd = _find_make()
  35. for key, value in env_vars.items():
  36. env.append(f'{key}={value}')
  37. if cli.config.general.verbose:
  38. env.append('VERBOSE=true')
  39. return [make_cmd, *(['-n'] if dry_run else []), *get_make_parallel_args(parallel), *env, target]
  40. def create_make_command(keyboard, keymap, target=None, dry_run=False, parallel=1, **env_vars):
  41. """Create a make compile command
  42. Args:
  43. keyboard
  44. The path of the keyboard, for example 'plank'
  45. keymap
  46. The name of the keymap, for example 'algernon'
  47. target
  48. Usually a bootloader.
  49. dry_run
  50. make -n -- don't actually build
  51. parallel
  52. The number of make jobs to run in parallel
  53. **env_vars
  54. Environment variables to be passed to make.
  55. Returns:
  56. A command that can be run to make the specified keyboard and keymap
  57. """
  58. make_args = [keyboard, keymap]
  59. if target:
  60. make_args.append(target)
  61. return create_make_target(':'.join(make_args), dry_run=dry_run, parallel=parallel, **env_vars)
  62. def get_make_parallel_args(parallel=1):
  63. """Returns the arguments for running the specified number of parallel jobs.
  64. """
  65. parallel_args = []
  66. if int(parallel) <= 0:
  67. # 0 or -1 means -j without argument (unlimited jobs)
  68. parallel_args.append('--jobs')
  69. else:
  70. parallel_args.append('--jobs=' + str(parallel))
  71. if int(parallel) != 1:
  72. # If more than 1 job is used, synchronize parallel output by target
  73. parallel_args.append('--output-sync=target')
  74. return parallel_args
  75. def compile_configurator_json(user_keymap, bootloader=None, parallel=1, clean=False, **env_vars):
  76. """Convert a configurator export JSON file into a C file and then compile it.
  77. Args:
  78. user_keymap
  79. A deserialized keymap export
  80. bootloader
  81. A bootloader to flash
  82. parallel
  83. The number of make jobs to run in parallel
  84. Returns:
  85. A command to run to compile and flash the C file.
  86. """
  87. # In case the user passes a keymap.json from a keymap directory directly to the CLI.
  88. # e.g.: qmk compile - < keyboards/clueboard/california/keymaps/default/keymap.json
  89. user_keymap["keymap"] = user_keymap.get("keymap", "default_json")
  90. keyboard_filesafe = user_keymap['keyboard'].replace('/', '_')
  91. target = f'{keyboard_filesafe}_{user_keymap["keymap"]}'
  92. intermediate_output = Path(f'{INTERMEDIATE_OUTPUT_PREFIX}{keyboard_filesafe}_{user_keymap["keymap"]}')
  93. keymap_dir = intermediate_output / 'src'
  94. keymap_json = keymap_dir / 'keymap.json'
  95. if clean:
  96. if intermediate_output.exists():
  97. shutil.rmtree(intermediate_output)
  98. # begin with making the deepest folder in the tree
  99. keymap_dir.mkdir(exist_ok=True, parents=True)
  100. # Compare minified to ensure consistent comparison
  101. new_content = json.dumps(user_keymap, separators=(',', ':'))
  102. if keymap_json.exists():
  103. old_content = json.dumps(json.loads(keymap_json.read_text(encoding='utf-8')), separators=(',', ':'))
  104. if old_content == new_content:
  105. new_content = None
  106. # Write the keymap.json file if different
  107. if new_content:
  108. keymap_json.write_text(new_content, encoding='utf-8')
  109. # Return a command that can be run to make the keymap and flash if given
  110. verbose = 'true' if cli.config.general.verbose else 'false'
  111. color = 'true' if cli.config.general.color else 'false'
  112. make_command = [_find_make()]
  113. if not cli.config.general.verbose:
  114. make_command.append('-s')
  115. make_command.extend([
  116. *get_make_parallel_args(parallel),
  117. '-r',
  118. '-R',
  119. '-f',
  120. 'builddefs/build_keyboard.mk',
  121. ])
  122. if bootloader:
  123. make_command.append(bootloader)
  124. make_command.extend([
  125. f'KEYBOARD={user_keymap["keyboard"]}',
  126. f'KEYMAP={user_keymap["keymap"]}',
  127. f'KEYBOARD_FILESAFE={keyboard_filesafe}',
  128. f'TARGET={target}',
  129. f'INTERMEDIATE_OUTPUT={intermediate_output}',
  130. f'MAIN_KEYMAP_PATH_1={intermediate_output}',
  131. f'MAIN_KEYMAP_PATH_2={intermediate_output}',
  132. f'MAIN_KEYMAP_PATH_3={intermediate_output}',
  133. f'MAIN_KEYMAP_PATH_4={intermediate_output}',
  134. f'MAIN_KEYMAP_PATH_5={intermediate_output}',
  135. f'KEYMAP_JSON={keymap_json}',
  136. f'KEYMAP_PATH={keymap_dir}',
  137. f'VERBOSE={verbose}',
  138. f'COLOR={color}',
  139. 'SILENT=false',
  140. 'QMK_BIN="qmk"',
  141. ])
  142. for key, value in env_vars.items():
  143. make_command.append(f'{key}={value}')
  144. return make_command
  145. def parse_configurator_json(configurator_file):
  146. """Open and parse a configurator json export
  147. """
  148. user_keymap = json_load(configurator_file)
  149. # Validate against the jsonschema
  150. try:
  151. validate(user_keymap, 'qmk.keymap.v1')
  152. except jsonschema.ValidationError as e:
  153. cli.log.error(f'Invalid JSON keymap: {configurator_file} : {e.message}')
  154. exit(1)
  155. keyboard = user_keymap['keyboard']
  156. aliases = json_load(Path('data/mappings/keyboard_aliases.hjson'))
  157. while keyboard in aliases:
  158. last_keyboard = keyboard
  159. keyboard = aliases[keyboard].get('target', keyboard)
  160. if keyboard == last_keyboard:
  161. break
  162. user_keymap['keyboard'] = keyboard
  163. return user_keymap
  164. def build_environment(args):
  165. """Common processing for cli.args.env
  166. """
  167. envs = {}
  168. for env in args:
  169. if '=' in env:
  170. key, value = env.split('=', 1)
  171. envs[key] = value
  172. else:
  173. cli.log.warning('Invalid environment variable: %s', env)
  174. return envs
  175. def in_virtualenv():
  176. """Check if running inside a virtualenv.
  177. Based on https://stackoverflow.com/a/1883251
  178. """
  179. active_prefix = getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix
  180. return active_prefix != sys.prefix
  181. def dump_lines(output_file, lines, quiet=True):
  182. """Handle dumping to stdout or file
  183. Creates parent folders if required
  184. """
  185. generated = '\n'.join(lines) + '\n'
  186. if output_file and output_file.name != '-':
  187. output_file.parent.mkdir(parents=True, exist_ok=True)
  188. if output_file.exists():
  189. output_file.replace(output_file.parent / (output_file.name + '.bak'))
  190. output_file.write_text(generated, encoding='utf-8')
  191. if not quiet:
  192. cli.log.info(f'Wrote {output_file.name} to {output_file}.')
  193. else:
  194. print(generated)