"""Show or compare the config Klipper builds from macros/klipper-macros.cfg. Klipper expands [include ...] in order and merges sections with the same name (the last value of an option wins). This script does the same, so a refactor can be checked for unintended changes. python tools/effective_config.py list sections of the working tree python tools/effective_config.py HEAD compare HEAD with the working tree python tools/effective_config.py A B compare two git refs python tools/effective_config.py HEAD -v also print old/new values """ import configparser import os import re import subprocess import sys import tempfile ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE = os.path.join('macros', 'klipper-macros.cfg') def expand(path): lines = [] with open(path, encoding='utf-8') as f: for line in f.read().replace('\r\n', '\n').split('\n'): m = re.match(r'^\[include ([^\]]+)\]', line.split('#')[0]) if m: inc = os.path.join(os.path.dirname(path), m.group(1).strip()) lines += expand(inc) else: lines.append(line) return lines def load(root): cp = configparser.RawConfigParser(strict=False, inline_comment_prefixes=(';', '#')) cp.read_string('\n'.join(expand(os.path.join(root, BASE)))) return {s: dict(cp.items(s)) for s in cp.sections()} def checkout(ref, tmp): archive = subprocess.run(['git', '-C', ROOT, 'archive', ref, 'macros'], check=True, capture_output=True).stdout subprocess.run(['tar', '-x', '-C', tmp], input=archive, check=True) return tmp def main(argv): verbose = '-v' in argv refs = [a for a in argv if a != '-v'] with tempfile.TemporaryDirectory() as t1, tempfile.TemporaryDirectory() as t2: if not refs: for s in sorted(load(ROOT)): print(s) return 0 old = load(checkout(refs[0], t1)) new = load(checkout(refs[1], t2) if len(refs) > 1 else ROOT) added, removed = sorted(set(new) - set(old)), sorted(set(old) - set(new)) changed = 0 for s in added: print('added ', s) for s in removed: print('removed ', s) for s in sorted(set(old) & set(new)): keys = sorted(k for k in set(old[s]) | set(new[s]) if old[s].get(k) != new[s].get(k)) if keys: changed += 1 print('changed ', s, keys) if verbose: for k in keys: print(' old %s: %r' % (k, old[s].get(k))) print(' new %s: %r' % (k, new[s].get(k))) print('%d sections, %d added, %d removed, %d changed' % (len(new), len(added), len(removed), changed)) return 0 if __name__ == '__main__': sys.exit(main(sys.argv[1:]))