|
| 1 | +"""This script automates the copying of the default keymap into your own keymap. |
| 2 | +""" |
| 3 | +import re |
| 4 | +import sys |
| 5 | +import os |
| 6 | + |
| 7 | +from qmk.constants import QMK_FIRMWARE |
| 8 | +from qmk.path import normpath |
| 9 | +from milc import cli |
| 10 | + |
| 11 | + |
| 12 | +def eprint(*args, **kwargs): |
| 13 | + print(*args, file=sys.stderr, **kwargs) |
| 14 | + |
| 15 | + |
| 16 | +fileHeader = """\ |
| 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-confupdate -i {0} -r {1}` |
| 36 | + */ |
| 37 | +
|
| 38 | +#pragma once |
| 39 | +""" |
| 40 | + |
| 41 | + |
| 42 | +def collect_defines(filepath): |
| 43 | + with open(filepath, 'r') 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 | + |
| 57 | +def 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 | + |
| 79 | +def migrate_chconf_h(to_override, outfile): |
| 80 | + print(fileHeader.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 | + |
| 89 | +def migrate_halconf_h(to_override, outfile): |
| 90 | + print(fileHeader.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 | + |
| 99 | +def migrate_mcuconf_h(to_override, outfile): |
| 100 | + print(fileHeader.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, help='Specify input config file.') |
| 111 | +@cli.argument('-r', '--reference', type=normpath, arg_only=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.subcommand('Generates a migrated ChibiOS configuration file, as a result of comparing the input against a reference') |
| 115 | +def chibios_confmigrate(cli): |
| 116 | + """Generates a usable ChibiOS replacement configuration file, based on a fully-defined conf and a reference config. |
| 117 | + """ |
| 118 | + |
| 119 | + input_defs = collect_defines(cli.args.input) |
| 120 | + reference_defs = collect_defines(cli.args.reference) |
| 121 | + |
| 122 | + (to_override, not_present_in_input, not_present_in_reference) = check_diffs(input_defs, reference_defs) |
| 123 | + |
| 124 | + if len(not_present_in_input) > 0: |
| 125 | + eprint("Keys not in input, but present inside reference (potential manual migration required):") |
| 126 | + for key in not_present_in_input: |
| 127 | + eprint(" %s" % (key)) |
| 128 | + |
| 129 | + if len(not_present_in_reference) > 0: |
| 130 | + eprint("Keys not in reference, but present inside input (potential manual migration required):") |
| 131 | + for key in not_present_in_reference: |
| 132 | + eprint(" %s" % (key)) |
| 133 | + |
| 134 | + if len(to_override) == 0: |
| 135 | + eprint('No overrides found! If there were no missing keys above, it should be safe to delete the input file.') |
| 136 | + if cli.args.delete: |
| 137 | + os.remove(cli.args.input) |
| 138 | + else: |
| 139 | + eprint('Overrides found:') |
| 140 | + for override in to_override: |
| 141 | + 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"))) |
| 142 | + |
| 143 | + eprint('--------------------------------------') |
| 144 | + |
| 145 | + if "CHCONF_H" in input_defs["dict"] or "_CHCONF_H_" in input_defs["dict"]: |
| 146 | + migrate_chconf_h(to_override, outfile=sys.stdout) |
| 147 | + if cli.args.overwrite: |
| 148 | + with open(cli.args.input, "w") as out_file: |
| 149 | + migrate_chconf_h(to_override, outfile=out_file) |
| 150 | + |
| 151 | + elif "HALCONF_H" in input_defs["dict"] or "_HALCONF_H_" in input_defs["dict"]: |
| 152 | + migrate_halconf_h(to_override, outfile=sys.stdout) |
| 153 | + if cli.args.overwrite: |
| 154 | + with open(cli.args.input, "w") as out_file: |
| 155 | + migrate_halconf_h(to_override, outfile=out_file) |
| 156 | + |
| 157 | + elif "MCUCONF_H" in input_defs["dict"] or "_MCUCONF_H_" in input_defs["dict"]: |
| 158 | + migrate_mcuconf_h(to_override, outfile=sys.stdout) |
| 159 | + if cli.args.overwrite: |
| 160 | + with open(cli.args.input, "w") as out_file: |
| 161 | + migrate_mcuconf_h(to_override, outfile=out_file) |
0 commit comments