92 lines
3.2 KiB
Python
92 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Independent real-world cross-check for diffkit.
|
|
|
|
The self-test uses GNU `diff` output on synthetic files. This one uses a real
|
|
repository: it takes the diffs produced by `git diff` for the most recent commit
|
|
of a repo, applies each one with diffkit, and compares the result byte-for-byte
|
|
against what git itself says the file looks like at HEAD (`git show HEAD:path`).
|
|
|
|
Usage: python3 verify_realrepo.py [repo] [rev] [max_files]
|
|
Exit code 0 iff every applicable file matched.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
sys.path.insert(0, HERE)
|
|
import diffkit # noqa: E402
|
|
|
|
MAX_BYTES = 400_000
|
|
|
|
|
|
def git(repo: str, *args: str) -> tuple[int, bytes]:
|
|
r = subprocess.run(["git", "-C", repo, *args], capture_output=True)
|
|
return r.returncode, r.stdout
|
|
|
|
|
|
def main() -> int:
|
|
repo = sys.argv[1] if len(sys.argv) > 1 else "/root/troupe-standup"
|
|
rev = sys.argv[2] if len(sys.argv) > 2 else "HEAD~1"
|
|
limit = int(sys.argv[3]) if len(sys.argv) > 3 else 15
|
|
verbose = os.environ.get("VERBOSE") == "1"
|
|
|
|
rc, out = git(repo, "diff", "--name-only", "-r", rev, "HEAD")
|
|
if rc != 0:
|
|
print("git diff failed for %s..HEAD" % rev)
|
|
return 2
|
|
names = [n for n in out.decode("utf-8", "replace").split("\n") if n]
|
|
print("repo=%s rev=%s..HEAD %d changed paths" % (repo, rev, len(names)))
|
|
|
|
checked = passed = skipped = 0
|
|
for name in names:
|
|
if checked >= limit:
|
|
break
|
|
rc_old, old = git(repo, "show", "%s:%s" % (rev, name))
|
|
rc_new, new = git(repo, "show", "HEAD:%s" % name)
|
|
if rc_old != 0 or rc_new != 0:
|
|
skipped += 1
|
|
if verbose:
|
|
print(" skip %-60s (added or deleted in this commit)" % name)
|
|
continue
|
|
if b"\x00" in old or b"\x00" in new or max(len(old), len(new)) > MAX_BYTES:
|
|
skipped += 1
|
|
if verbose:
|
|
print(" skip %-60s (binary or >%d bytes)" % (name, MAX_BYTES))
|
|
continue
|
|
|
|
rc_d, d = git(repo, "diff", "--no-color", "-U3", rev, "HEAD", "--", name)
|
|
if rc_d != 0 or not d.strip():
|
|
skipped += 1
|
|
if verbose:
|
|
print(" skip %-60s (no textual diff)" % name)
|
|
continue
|
|
|
|
old_s = old.decode("utf-8")
|
|
new_s = new.decode("utf-8")
|
|
diff_s = d.decode("utf-8")
|
|
checked += 1
|
|
try:
|
|
got = diffkit.apply_one(diff_s, old_s)
|
|
except Exception as e: # noqa: BLE001
|
|
print(" FAIL %-60s raised %s: %s" % (name, type(e).__name__, e))
|
|
continue
|
|
if got == new_s:
|
|
passed += 1
|
|
print(" ok %-60s %d bytes, %d hunks"
|
|
% (name, len(new_s.encode()), len(diffkit.parse_unified_diff(diff_s)[0].hunks)))
|
|
else:
|
|
print(" FAIL %-60s mismatch (got %d bytes, want %d)"
|
|
% (name, len(got.encode()), len(new_s.encode())))
|
|
|
|
print("\n%d/%d applicable files reproduced exactly (%d skipped)"
|
|
% (passed, checked, skipped))
|
|
return 0 if checked > 0 and passed == checked else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|