at master 7.0 kB view raw
1"""This script automates the copying of the default keymap into your own keymap. 2""" 3import re 4import sys 5import os 6 7from qmk.constants import QMK_FIRMWARE 8from qmk.path import normpath 9from milc import cli 10 11 12def eprint(*args, **kwargs): 13 print(*args, file=sys.stderr, **kwargs) 14 15 16file_header = """\ 17/* Copyright 2020 QMK 18 * 19 * This program is free software: you can redistribute it and/or modify 20 * it under the terms of the GNU General Public License as published by 21 * the Free Software Foundation, either version 2 of the License, or 22 * (at your option) any later version. 23 * 24 * This program is distributed in the hope that it will be useful, 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * GNU General Public License for more details. 28 * 29 * You should have received a copy of the GNU General Public License 30 * along with this program. If not, see <http://www.gnu.org/licenses/>. 31 */ 32 33/* 34 * This file was auto-generated by: 35 * `qmk chibios-confmigrate -i {0} -r {1}` 36 */ 37 38#pragma once 39""" 40 41 42def collect_defines(filepath): 43 with open(filepath, 'r', encoding='utf-8') as f: 44 content = f.read() 45 define_search = re.compile(r'(?m)^#\s*define\s+(?:.*\\\r?\n)*.*$', re.MULTILINE) 46 value_search = re.compile(r'^#\s*define\s+(?P<name>[a-zA-Z0-9_]+(\([^\)]*\))?)\s*(?P<value>.*)', re.DOTALL) 47 define_matches = define_search.findall(content) 48 49 defines = {"keys": [], "dict": {}} 50 for define_match in define_matches: 51 value_match = value_search.search(define_match) 52 defines["keys"].append(value_match.group("name")) 53 defines["dict"][value_match.group("name")] = value_match.group("value") 54 return defines 55 56 57def check_diffs(input_defs, reference_defs): 58 not_present_in_input = [] 59 not_present_in_reference = [] 60 to_override = [] 61 62 for key in reference_defs["keys"]: 63 if key not in input_defs["dict"]: 64 not_present_in_input.append(key) 65 continue 66 67 for key in input_defs["keys"]: 68 if key not in input_defs["dict"]: 69 not_present_in_input.append(key) 70 continue 71 72 for key in input_defs["keys"]: 73 if key in reference_defs["keys"] and input_defs["dict"][key] != reference_defs["dict"][key]: 74 to_override.append((key, input_defs["dict"][key])) 75 76 return (to_override, not_present_in_input, not_present_in_reference) 77 78 79def migrate_chconf_h(to_override, outfile): 80 print(file_header.format(cli.args.input.relative_to(QMK_FIRMWARE), cli.args.reference.relative_to(QMK_FIRMWARE)), file=outfile) 81 82 for override in to_override: 83 print("#define %s %s" % (override[0], override[1]), file=outfile) 84 print("", file=outfile) 85 86 print("#include_next <chconf.h>\n", file=outfile) 87 88 89def migrate_halconf_h(to_override, outfile): 90 print(file_header.format(cli.args.input.relative_to(QMK_FIRMWARE), cli.args.reference.relative_to(QMK_FIRMWARE)), file=outfile) 91 92 for override in to_override: 93 print("#define %s %s" % (override[0], override[1]), file=outfile) 94 print("", file=outfile) 95 96 print("#include_next <halconf.h>\n", file=outfile) 97 98 99def migrate_mcuconf_h(to_override, outfile): 100 print(file_header.format(cli.args.input.relative_to(QMK_FIRMWARE), cli.args.reference.relative_to(QMK_FIRMWARE)), file=outfile) 101 102 print("#include_next <mcuconf.h>\n", file=outfile) 103 104 for override in to_override: 105 print("#undef %s" % (override[0]), file=outfile) 106 print("#define %s %s" % (override[0], override[1]), file=outfile) 107 print("", file=outfile) 108 109 110@cli.argument('-i', '--input', type=normpath, arg_only=True, required=True, help='Specify input config file.') 111@cli.argument('-r', '--reference', type=normpath, arg_only=True, required=True, help='Specify the reference file to compare against') 112@cli.argument('-o', '--overwrite', arg_only=True, action='store_true', help='Overwrites the input file during migration.') 113@cli.argument('-d', '--delete', arg_only=True, action='store_true', help='If the file has no overrides, migration will delete the input file.') 114@cli.argument('-f', '--force', arg_only=True, action='store_true', help='Re-migrates an already migrated file, even if it doesn\'t detect a full ChibiOS config.') 115@cli.subcommand('Generates a migrated ChibiOS configuration file, as a result of comparing the input against a reference') 116def chibios_confmigrate(cli): 117 """Generates a usable ChibiOS replacement configuration file, based on a fully-defined conf and a reference config. 118 """ 119 120 input_defs = collect_defines(cli.args.input) 121 reference_defs = collect_defines(cli.args.reference) 122 123 (to_override, not_present_in_input, not_present_in_reference) = check_diffs(input_defs, reference_defs) 124 125 if len(not_present_in_input) > 0: 126 eprint("Keys not in input, but present inside reference (potential manual migration required):") 127 for key in not_present_in_input: 128 eprint(" %s" % (key)) 129 130 if len(not_present_in_reference) > 0: 131 eprint("Keys not in reference, but present inside input (potential manual migration required):") 132 for key in not_present_in_reference: 133 eprint(" %s" % (key)) 134 135 if len(to_override) == 0: 136 eprint('No overrides found! If there were no missing keys above, it should be safe to delete the input file.') 137 if cli.args.delete: 138 os.remove(cli.args.input) 139 else: 140 eprint('Overrides found:') 141 for override in to_override: 142 eprint("%40s: %s -> %s" % (override[0], reference_defs["dict"][override[0]].encode('unicode_escape').decode("utf-8"), override[1].encode('unicode_escape').decode("utf-8"))) 143 144 eprint('--------------------------------------') 145 146 if cli.args.input.name == "chconf.h" and ("CHCONF_H" in input_defs["dict"] or "_CHCONF_H_" in input_defs["dict"] or cli.args.force): 147 migrate_chconf_h(to_override, outfile=sys.stdout) 148 if cli.args.overwrite: 149 with open(cli.args.input, "w", encoding='utf-8') as out_file: 150 migrate_chconf_h(to_override, outfile=out_file) 151 152 elif cli.args.input.name == "halconf.h" and ("HALCONF_H" in input_defs["dict"] or "_HALCONF_H_" in input_defs["dict"] or cli.args.force): 153 migrate_halconf_h(to_override, outfile=sys.stdout) 154 if cli.args.overwrite: 155 with open(cli.args.input, "w", encoding='utf-8') as out_file: 156 migrate_halconf_h(to_override, outfile=out_file) 157 158 elif cli.args.input.name == "mcuconf.h" and ("MCUCONF_H" in input_defs["dict"] or "_MCUCONF_H_" in input_defs["dict"] or cli.args.force): 159 migrate_mcuconf_h(to_override, outfile=sys.stdout) 160 if cli.args.overwrite: 161 with open(cli.args.input, "w", encoding='utf-8') as out_file: 162 migrate_mcuconf_h(to_override, outfile=out_file)