info_json.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. """Keyboard information script.
  2. Compile an info.json for a particular keyboard and pretty-print it.
  3. """
  4. import json
  5. from argcomplete.completers import FilesCompleter
  6. from jsonschema import Draft202012Validator, RefResolver, validators
  7. from milc import cli
  8. from pathlib import Path
  9. from qmk.decorators import automagic_keyboard, automagic_keymap
  10. from qmk.info import info_json
  11. from qmk.json_encoders import InfoJSONEncoder
  12. from qmk.json_schema import compile_schema_store
  13. from qmk.keyboard import keyboard_completer, keyboard_folder
  14. from qmk.path import is_keyboard, normpath
  15. def pruning_validator(validator_class):
  16. """Extends Draft202012Validator to remove properties that aren't specified in the schema.
  17. """
  18. validate_properties = validator_class.VALIDATORS["properties"]
  19. def remove_additional_properties(validator, properties, instance, schema):
  20. for prop in list(instance.keys()):
  21. if prop not in properties:
  22. del instance[prop]
  23. for error in validate_properties(validator, properties, instance, schema):
  24. yield error
  25. return validators.extend(validator_class, {"properties": remove_additional_properties})
  26. def strip_info_json(kb_info_json):
  27. """Remove the API-only properties from the info.json.
  28. """
  29. schema_store = compile_schema_store()
  30. pruning_draft_validator = pruning_validator(Draft202012Validator)
  31. schema = schema_store['qmk.keyboard.v1']
  32. resolver = RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store)
  33. validator = pruning_draft_validator(schema, resolver=resolver).validate
  34. return validator(kb_info_json)
  35. @cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to show info for.')
  36. @cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.')
  37. @cli.argument('-o', '--output', arg_only=True, completer=FilesCompleter, help='Write the output the specified file, overwriting if necessary.')
  38. @cli.argument('-ow', '--overwrite', arg_only=True, action='store_true', help='Overwrite the existing info.json. (Overrides the location of --output)')
  39. @cli.subcommand('Generate an info.json file for a keyboard.', hidden=False if cli.config.user.developer else True)
  40. @automagic_keyboard
  41. @automagic_keymap
  42. def generate_info_json(cli):
  43. """Generate an info.json file for a keyboard
  44. """
  45. # Determine our keyboard(s)
  46. if not cli.config.generate_info_json.keyboard:
  47. cli.log.error('Missing parameter: --keyboard')
  48. cli.subcommands['info'].print_help()
  49. return False
  50. if not is_keyboard(cli.config.generate_info_json.keyboard):
  51. cli.log.error('Invalid keyboard: "%s"', cli.config.generate_info_json.keyboard)
  52. return False
  53. if cli.args.overwrite:
  54. output_path = (Path('keyboards') / cli.config.generate_info_json.keyboard / 'info.json').resolve()
  55. if cli.args.output:
  56. cli.log.warning('Overwriting user supplied --output with %s', output_path)
  57. cli.args.output = output_path
  58. # Build the info.json file
  59. kb_info_json = info_json(cli.config.generate_info_json.keyboard)
  60. strip_info_json(kb_info_json)
  61. info_json_text = json.dumps(kb_info_json, indent=4, cls=InfoJSONEncoder)
  62. if cli.args.output:
  63. # Write to a file
  64. output_path = normpath(cli.args.output)
  65. if output_path.exists():
  66. cli.log.warning('Overwriting output file %s', output_path)
  67. output_path.write_text(info_json_text + '\n')
  68. cli.log.info('Wrote info.json to %s.', output_path)
  69. else:
  70. # Display the results
  71. print(info_json_text)