151 lines
4.9 KiB
Python
151 lines
4.9 KiB
Python
import gzip
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
def fetch_dumps(file):
|
|
files = { }
|
|
cur_file = None
|
|
cur_dump = None
|
|
for line in file:
|
|
line = line.rstrip()
|
|
if line.startswith("=="):
|
|
name = line[2:].strip()
|
|
cur_file = { }
|
|
files[name] = cur_file
|
|
elif line.startswith("--"):
|
|
name = line[2:].strip()
|
|
cur_dump = []
|
|
cur_file[name] = cur_dump
|
|
elif cur_dump is not None:
|
|
cur_dump.append(line)
|
|
return files
|
|
|
|
def diff_dump(dump, ref, file, runner, ref_runner):
|
|
num_lines = max(len(dump), len(ref))
|
|
stack = []
|
|
has_diff = False
|
|
|
|
for ix in range(num_lines):
|
|
dline = dump[ix] if ix < len(dump) else ""
|
|
rline = ref[ix] if ix < len(ref) else ""
|
|
|
|
if dline == rline:
|
|
if "{" in dline:
|
|
stack.append(dline)
|
|
elif "}" in dline:
|
|
stack.pop()
|
|
else:
|
|
span = 2
|
|
start = max(0, ix - span)
|
|
stop = ix + span + 1
|
|
|
|
has_diff = True
|
|
|
|
print(f"== {file}")
|
|
print()
|
|
print(" ".join(s.strip().rstrip("{ ") for s in stack))
|
|
|
|
print()
|
|
print(f"-- {runner}")
|
|
print()
|
|
for lix in range(start, stop):
|
|
dl = dump[lix] if lix < len(dump) else ""
|
|
rl = ref[lix] if lix < len(ref) else ""
|
|
prefix = "> " if dl != rl else " "
|
|
print(prefix + dl)
|
|
|
|
print()
|
|
print(f"-- {ref_runner}")
|
|
print()
|
|
for lix in range(start, stop):
|
|
dl = dump[lix] if lix < len(dump) else ""
|
|
rl = ref[lix] if lix < len(ref) else ""
|
|
prefix = "> " if dl != rl else " "
|
|
print(prefix + rl)
|
|
|
|
print()
|
|
break
|
|
return has_diff
|
|
|
|
def do_compress(argv):
|
|
with gzip.open(argv.o, "wt", compresslevel=8) as outf:
|
|
for file in os.listdir(argv.directory):
|
|
name = file[:-4] if file.endswith(".txt") else file
|
|
path = os.path.join(argv.directory, file)
|
|
print(f"== {name}", file=outf)
|
|
with open(path, "rt") as inf:
|
|
outf.writelines(inf)
|
|
|
|
def do_list(argv):
|
|
entries = set()
|
|
for file in os.listdir(argv.directory):
|
|
path = os.path.join(argv.directory, file)
|
|
with gzip.open(path, "rt") as inf:
|
|
for line in inf:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
m = re.match(r"--\s*(\d+)\s+(.+)", line)
|
|
if m:
|
|
frame = m.group(1)
|
|
path = m.group(2)
|
|
entries.add((frame, path))
|
|
with open(argv.o, "wt") as outf:
|
|
for frame, path in entries:
|
|
print(f"0000000000000000 {frame} {path}", file=outf)
|
|
|
|
def do_diff(argv):
|
|
with gzip.open(argv.ref, "rt") as inf:
|
|
ref_dumps = fetch_dumps(inf)
|
|
|
|
ref_tuple = next(iter(ref_dumps.items()), None)
|
|
if not ref_tuple:
|
|
return
|
|
|
|
has_diff = False
|
|
|
|
ref_runner, ref_file = ref_tuple
|
|
for file in os.listdir(argv.directory):
|
|
path = os.path.join(argv.directory, file)
|
|
with gzip.open(path, "rt") as inf:
|
|
dumps = fetch_dumps(inf)
|
|
for runner, files in dumps.items():
|
|
for file, dump in files.items():
|
|
ref = ref_file[file]
|
|
if diff_dump(dump, ref, file, runner, ref_runner):
|
|
has_diff = True
|
|
|
|
if has_diff:
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
from argparse import ArgumentParser
|
|
|
|
parser = ArgumentParser(prog="hash_diff.py")
|
|
parser.add_argument("--verbose", action="store_true", help="Show extra information")
|
|
|
|
subparsers = parser.add_subparsers(metavar="cmd")
|
|
|
|
parser_compress = subparsers.add_parser("compress", help="Compress files")
|
|
parser_compress.add_argument("directory", help="Directory of hash files to compress")
|
|
parser_compress.add_argument("-o", metavar="output.gz", required=True, help="Output .gz filename")
|
|
parser_compress.set_defaults(func=do_compress)
|
|
|
|
parser_dump = subparsers.add_parser("list", help="List all files from other dumps in hash check compatible format")
|
|
parser_dump.add_argument("directory", help="Directory of .gz dump files generated by 'compress'")
|
|
parser_dump.add_argument("-o", metavar="output.txt", required=True, help="Output .txt filename")
|
|
parser_dump.set_defaults(func=do_list)
|
|
|
|
parser_diff = subparsers.add_parser("diff", help="Compare dumps")
|
|
parser_diff.add_argument("directory", help="Directory of .gz dump files generated by 'compress'")
|
|
parser_diff.add_argument("--ref", metavar="ref.gz", required=True, help="Reference hash dump .gz")
|
|
parser_diff.set_defaults(func=do_diff)
|
|
|
|
argv = parser.parse_args()
|
|
if "func" not in argv:
|
|
parser.print_help()
|
|
else:
|
|
argv.func(argv)
|
|
|