at master 3.5 kB view raw
1"""Migrate keyboard configuration to "Data Driven" 2""" 3import json 4from pathlib import Path 5from dotty_dict import dotty 6 7from milc import cli 8 9from qmk.keyboard import keyboard_completer, keyboard_folder 10from qmk.info import info_json, find_info_json 11from qmk.json_encoders import InfoJSONEncoder 12from qmk.json_schema import json_load 13 14 15def _candidate_files(keyboard): 16 kb_dir = Path(keyboard) 17 18 cur_dir = Path('keyboards') 19 files = [] 20 for dir in kb_dir.parts: 21 cur_dir = cur_dir / dir 22 files.append(cur_dir / 'config.h') 23 files.append(cur_dir / 'rules.mk') 24 25 return [file for file in files if file.exists()] 26 27 28@cli.argument('-f', '--filter', arg_only=True, action='append', default=[], help="Filter the performed migrations based on the supplied value. Supported format is 'KEY' located from 'data/mappings'. May be passed multiple times.") 29@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, required=True, help='The keyboard\'s name') 30@cli.subcommand('Migrate keyboard config to "Data Driven".', hidden=True) 31def migrate(cli): 32 """Migrate keyboard configuration to "Data Driven" 33 """ 34 # Merge mappings as we do not care to where "KEY" is found just that its removed 35 info_config_map = json_load(Path('data/mappings/info_config.hjson')) 36 info_rules_map = json_load(Path('data/mappings/info_rules.hjson')) 37 info_map = {**info_config_map, **info_rules_map} 38 39 # Parse target info.json which will receive updates 40 target_info = Path(find_info_json(cli.args.keyboard)[0]) 41 info_data = dotty(json_load(target_info)) 42 43 # Already parsed used for updates 44 kb_info_json = dotty(info_json(cli.args.keyboard)) 45 46 # List of candidate files 47 files = _candidate_files(cli.args.keyboard) 48 49 # Filter down keys if requested 50 keys = list(filter(lambda key: info_map[key].get("to_json", True), info_map.keys())) 51 if cli.args.filter: 52 keys = list(set(keys) & set(cli.args.filter)) 53 rejected = set(cli.args.filter) - set(keys) 54 for key in rejected: 55 cli.log.info(f'{{fg_yellow}}Skipping {key} as migration not possible...') 56 57 cli.log.info(f'{{fg_green}}Migrating keyboard {{fg_cyan}}{cli.args.keyboard}{{fg_green}}.{{fg_reset}}') 58 59 # Start migration 60 for file in files: 61 cli.log.info(f' Migrating file {file}') 62 file_contents = file.read_text(encoding='utf-8').split('\n') 63 for key in keys: 64 for num, line in enumerate(file_contents): 65 if line.startswith(f'{key} =') or line.startswith(f'#define {key} '): 66 cli.log.info(f' Migrating {key}...') 67 68 while line.rstrip().endswith('\\'): 69 file_contents.pop(num) 70 line = file_contents[num] 71 file_contents.pop(num) 72 73 update_key = info_map[key]["info_key"] 74 if update_key in kb_info_json: 75 info_data[update_key] = kb_info_json[update_key] 76 77 file.write_text('\n'.join(file_contents), encoding='utf-8') 78 79 # Finally write out updated info.json 80 cli.log.info(f' Updating {target_info}') 81 target_info.write_text(json.dumps(info_data.to_dict(), cls=InfoJSONEncoder, sort_keys=True)) 82 83 cli.log.info(f'{{fg_green}}Migration of keyboard {{fg_cyan}}{cli.args.keyboard}{{fg_green}} complete!{{fg_reset}}') 84 cli.log.info(f"Verify build with {{fg_yellow}}qmk compile -kb {cli.args.keyboard} -km default{{fg_reset}}.")