#!/usr/bin/env python3 import argparse from hashlib import sha256 import os import subprocess import sys def _main(): args = _parse_args() args.func(args) def _parse_args(): parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest="command", required=True) approve_parser = subparsers.add_parser("approve") approve_parser.set_defaults(func=_approve) approve_parser.add_argument("--all", "-a", action="store_true") diff_parser = subparsers.add_parser("diff") diff_parser.set_defaults(func=_diff) diff_parser.add_argument("code", nargs="?") ls_parser = subparsers.add_parser("ls") ls_parser.set_defaults(func=_ls) reject_parser = subparsers.add_parser("reject") reject_parser.set_defaults(func=_reject) reject_parser.add_argument("--all", "-a", action="store_true") return parser.parse_args() def _approve(args): if args.all: for path in _find_actual_paths(): expected_path = _actual_path_to_expected_path(path) print("replace\n {}\nwith\n {}".format(expected_path, path), file=sys.stderr) os.replace(path, expected_path) else: raise Exception("not implemented yet") def _diff(args): if args.code is None: for actual_path in _find_actual_paths(): _render_diff(actual_path) print() else: matches = [] for actual_path in _find_actual_paths(): name = _path_to_name(actual_path) code = _name_to_code(name) if code.startswith(args.code): matches.append(actual_path) if len(matches) == 0: raise ValueError(f"could not find {args.code}") elif len(matches) > 1: raise ValueError(f"multiple matches for {args.code}") else: actual_path = matches[0] _render_diff(actual_path) def _render_diff(actual_path): expected_path = _actual_path_to_expected_path(actual_path) name = _path_to_name(actual_path) code = _name_to_code(name) print("Code:", code) print("Name:", name, flush=True) subprocess.run(["colordiff", "-u", "--new-file", expected_path, actual_path]) def _ls(args): for actual_path in _find_actual_paths(): name = _path_to_name(actual_path) code = _name_to_code(name) print("Code:", code) print("Name:", name) print() def _reject(args): if args.all: for path in _find_actual_paths(): print("delete\n {}".format(path), file=sys.stderr) os.unlink(path) else: raise Exception("not implemented yet") def _find_actual_paths(): for root, dirnames, filenames in os.walk(_snapshots_path()): for filename in filenames: path = os.path.join(root, filename) if _has_extension(path, "actual"): yield path def _snapshots_path(): return os.path.join(os.path.dirname(__file__), "snapshots") def _has_extension(path, extension): return os.path.splitext(path)[1] == "." + extension def _actual_path_to_expected_path(actual_path): return _replace_extension(actual_path, "expected") def _replace_extension(path, extension): return _remove_extension(path) + "." + extension def _remove_extension(path): return os.path.splitext(path)[0] def _path_to_name(path): return os.path.relpath(os.path.splitext(path)[0], _snapshots_path()) def _name_to_code(name): return sha256(name.encode("utf8")).hexdigest() if __name__ == "__main__": _main()