#!/usr/bin/env python3 """Porownuje SEMANTYKE (yaml.safe_load) wersji HEAD i roboczej kazdej zmienionej receptury. Wypisuje dla kazdego pliku: - klucze, ktore realnie zmienily wartosc - informacje, czy roznica jest wylacznie formatowaniem (te same dane, inny zapis) """ import subprocess import sys import yaml R = "/var/lib/pagan-sync/recipes" def sh(*args): return subprocess.run(args, cwd=R, capture_output=True, text=True) def load(text): return yaml.safe_load(text) def main(): st = sh("git", "status", "--porcelain") files = [] for line in st.stdout.splitlines(): if not line.strip(): continue code, path = line[:2], line[3:].strip() if code.strip() == "??": continue if not path.endswith(".yaml"): continue files.append(path) print(f"plikow do sprawdzenia: {len(files)}\n") bad = [] only_fmt = [] real = [] for path in files: try: head_text = sh("git", "show", f"HEAD:{path}").stdout except Exception as e: print(f"!! {path}: nie moge czytac HEAD ({e})") continue try: work_text = open(f"{R}/{path}", encoding="utf-8").read() except Exception as e: print(f"!! {path}: nie moge czytac pliku ({e})") continue try: a = load(head_text) b = load(work_text) except Exception as e: print(f"!! {path}: YAML nie parsuje sie: {e}") bad.append(path) continue if a == b: only_fmt.append(path) continue if not isinstance(a, dict) or not isinstance(b, dict): print(f"%% {path}: zmiana typu danych ({type(a).__name__} -> {type(b).__name__})") real.append((path, [""])) continue keys = sorted(set(a) | set(b)) diff_keys = [] for k in keys: va, vb = a.get(k, ""), b.get(k, "") if va != vb: diff_keys.append(k) real.append((path, diff_keys)) print(f"## {path}") for k in diff_keys: va, vb = a.get(k, ""), b.get(k, "") ra, rb = repr(va), repr(vb) if len(ra) > 160: ra = ra[:160] + f"...[len={len(str(va))}]" if len(rb) > 160: rb = rb[:160] + f"...[len={len(str(vb))}]" print(f" {k}:\n HEAD: {ra}\n WORK: {rb}") print() print("=" * 70) print(f"semantycznie identyczne (tylko formatowanie): {len(only_fmt)}") for p in only_fmt: print(f" ~ {p}") print(f"z realna zmiana tresci: {len(real)}") for p, ks in real: print(f" * {p}: {', '.join(ks)}") if bad: print(f"NIEPARSOWALNE: {len(bad)}") for p in bad: print(f" ! {p}") if __name__ == "__main__": sys.exit(main())