"""Keyboard information script. Compile an info.json for a particular keyboard and pretty-print it. """ import json from argcomplete.completers import FilesCompleter from jsonschema import Draft7Validator, RefResolver, validators from milc import cli from pathlib import Path from qmk.decorators import automagic_keyboard, automagic_keymap from qmk.info import info_json from qmk.json_encoders import InfoJSONEncoder from qmk.json_schema import compile_schema_store from qmk.keyboard import keyboard_completer, keyboard_folder from qmk.path import is_keyboard, normpath def pruning_validator(validator_class): """Extends Draft7Validator to remove properties that aren't specified in the schema. """ validate_properties = validator_class.VALIDATORS["properties"] def remove_additional_properties(validator, properties, instance, schema): for prop in list(instance.keys()): if prop not in properties: del instance[prop] for error in validate_properties(validator, properties, instance, schema): yield error return validators.extend(validator_class, {"properties": remove_additional_properties}) def strip_info_json(kb_info_json): """Remove the API-only properties from the info.json. """ schema_store = compile_schema_store() pruning_draft_7_validator = pruning_validator(Draft7Validator) schema = schema_store['qmk.keyboard.v1'] resolver = RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store) validator = pruning_draft_7_validator(schema, resolver=resolver).validate return validator(kb_info_json) @cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to show info for.') @cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.') @cli.argument('-o', '--output', arg_only=True, completer=FilesCompleter, help='Write the output the specified file, overwriting if necessary.') @cli.argument('-ow', '--overwrite', arg_only=True, action='store_true', help='Overwrite the existing info.json. (Overrides the location of --output)') @cli.subcommand('Generate an info.json file for a keyboard.', hidden=False if cli.config.user.developer else True) @automagic_keyboard @automagic_keymap def generate_info_json(cli): """Generate an info.json file for a keyboard """ # Determine our keyboard(s) if not cli.config.generate_info_json.keyboard: cli.log.error('Missing parameter: --keyboard') cli.subcommands['info'].print_help() return False if not is_keyboard(cli.config.generate_info_json.keyboard): cli.log.error('Invalid keyboard: "%s"', cli.config.generate_info_json.keyboard) return False if cli.args.overwrite: output_path = (Path('keyboards') / cli.config.generate_info_json.keyboard / 'info.json').resolve() if cli.args.output: cli.log.warning('Overwriting user supplied --output with %s', output_path) cli.args.output = output_path # Build the info.json file kb_info_json = info_json(cli.config.generate_info_json.keyboard) strip_info_json(kb_info_json) info_json_text = json.dumps(kb_info_json, indent=4, cls=InfoJSONEncoder) if cli.args.output: # Write to a file output_path = normpath(cli.args.output) if output_path.exists(): cli.log.warning('Overwriting output file %s', output_path) output_path.write_text(info_json_text + '\n') cli.log.info('Wrote info.json to %s.', output_path) else: # Display the results print(info_json_text)