def augment_community_info(src, dest): """Splice in any additional data into info.json """ info = json.loads(src.read_text()) template = json.loads(dest.read_text()) # merge community with template deep_update(info, template) # avoid assumptions on macro name by using the first available first_layout = next(iter(info["layouts"].values()))["layout"] # guess at width and height now its optional width, height = (0, 0) for item in first_layout: width = max(width, int(item["x"]) + 1) height = max(height, int(item["y"]) + 1) info["matrix_pins"] = { "cols": ["C2"] * width, "rows": ["D1"] * height, } # assume a 1:1 mapping on matrix to electrical for item in first_layout: item["matrix"] = [int(item["y"]), int(item["x"])] # finally write out the updated info.json dest.write_text(json.dumps(info, cls=InfoJSONEncoder))
def merge_info_jsons(keyboard, info_data): """Return a merged copy of all the info.json files for a keyboard. """ for info_file in find_info_json(keyboard): # Load and validate the JSON data new_info_data = json_load(info_file) if not isinstance(new_info_data, dict): _log_error( info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file), )) continue try: keyboard_validate(new_info_data) except jsonschema.ValidationError as e: json_path = '.'.join([str(p) for p in e.absolute_path]) cli.log.error('Not including data from file: %s', info_file) cli.log.error('\t%s: %s', json_path, e.message) continue # Merge layout data in if 'layout_aliases' in new_info_data: info_data['layout_aliases'] = { **info_data.get('layout_aliases', {}), **new_info_data['layout_aliases'] } del new_info_data['layout_aliases'] for layout_name, layout in new_info_data.get('layouts', {}).items(): if layout_name in info_data.get('layout_aliases', {}): _log_warning( info_data, f"info.json uses alias name {layout_name} instead of {info_data['layout_aliases'][layout_name]}" ) layout_name = info_data['layout_aliases'][layout_name] if layout_name in info_data['layouts']: for new_key, existing_key in zip( layout['layout'], info_data['layouts'][layout_name]['layout']): existing_key.update(new_key) else: layout['c_macro'] = False info_data['layouts'][layout_name] = layout # Update info_data with the new data if 'layouts' in new_info_data: del new_info_data['layouts'] deep_update(info_data, new_info_data) return info_data
def merge_info_jsons(keyboard, info_data): """Return a merged copy of all the info.json files for a keyboard. """ for info_file in find_info_json(keyboard): # Load and validate the JSON data new_info_data = json_load(info_file) if not isinstance(new_info_data, dict): _log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),)) continue try: validate(new_info_data, 'qmk.keyboard.v1') except jsonschema.ValidationError as e: json_path = '.'.join([str(p) for p in e.absolute_path]) cli.log.error('Not including data from file: %s', info_file) cli.log.error('\t%s: %s', json_path, e.message) continue # Merge layout data in if 'layout_aliases' in new_info_data: info_data['layout_aliases'] = {**info_data.get('layout_aliases', {}), **new_info_data['layout_aliases']} del new_info_data['layout_aliases'] for layout_name, layout in new_info_data.get('layouts', {}).items(): if layout_name in info_data.get('layout_aliases', {}): _log_warning(info_data, f"info.json uses alias name {layout_name} instead of {info_data['layout_aliases'][layout_name]}") layout_name = info_data['layout_aliases'][layout_name] if layout_name in info_data['layouts']: if len(info_data['layouts'][layout_name]['layout']) != len(layout['layout']): msg = 'Number of keys for %s does not match! info.json specifies %d keys, C macro specifies %d' _log_error(info_data, msg % (layout_name, len(layout['layout']), len(info_data['layouts'][layout_name]['layout']))) else: for new_key, existing_key in zip(layout['layout'], info_data['layouts'][layout_name]['layout']): existing_key.update(new_key) else: if not all('matrix' in key_data.keys() for key_data in layout['layout']): _log_error(info_data, f'Layout "{layout_name}" has no "matrix" definition in either "info.json" or "<keyboard>.h"!') else: layout['c_macro'] = False info_data['layouts'][layout_name] = layout # Update info_data with the new data if 'layouts' in new_info_data: del new_info_data['layouts'] deep_update(info_data, new_info_data) return info_data
def keymap_json(keyboard, keymap): """Generate the info.json data for a specific keymap. """ keymap_folder = locate_keymap(keyboard, keymap).parent # Files to scan keymap_config = keymap_folder / 'config.h' keymap_rules = keymap_folder / 'rules.mk' keymap_file = keymap_folder / 'keymap.json' # Build the info.json file kb_info_json = info_json(keyboard) # Merge in the data from keymap.json km_info_json = keymap_json_config(keyboard, keymap) if keymap_file.exists() else {} deep_update(kb_info_json, km_info_json) # Merge in the data from config.h, and rules.mk _extract_rules_mk(kb_info_json, parse_rules_mk_file(keymap_rules)) _extract_config_h(kb_info_json, parse_config_h_file(keymap_config)) return kb_info_json