#!/usr/bin/env fuchsia-vendored-python
# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
generate hash signature of a directory and optionally compare it to an existing
one

This script reads all files under DIR to generate SHA-1 hashes from their
content. By default, the hash signature is printed and the script exits.

The --compare SIGNATURE option can be used to check the hashes against a fixed
signature file. SIGNATURE should be the path to an input text file containing
one such signature. In this mode, the program's status will be 0 in case of
success, or 1 in case of failure.
"""

import argparse
import hashlib
import json
import os
import sys

SHA1_HEX_LEN = 40
CHUNK_SIZE = 4096
MESSAGE = """signature has changed:
  {changes}

(tip) To update the signature run:
   $ {name} \\\n   --header_paths {paths} \\\n   --header_dir {dir} \\\n   > {signature}"""


def main(name, argv):
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "--header_paths",
        required=True,
        nargs="*",
        help="array of paths to header files",
    )
    parser.add_argument(
        "--header_dir", required=True, help="path to header file directory"
    )
    parser.add_argument(
        "--compare", metavar="SIGNATURE", help="path to input signature file"
    )
    parser.add_argument(
        "--stamp", help="path to stamp file to write after completion"
    )

    args = parser.parse_args(argv)
    signatures = dir_signatures(args.header_paths, args.header_dir)

    if not args.compare:
        print(json.dumps(signatures, sort_keys=True, indent=4))
    elif not args.stamp:
        sys.exit("must use --stamp flag if comparing signature files")
    else:
        try:
            with open(args.compare, "rb") as file:
                try:
                    expected = json.load(file)
                except json.decoder.JSONDecodeError as e:
                    sys.exit(
                        f"{e}\nerror raised while loading json of: {args.compare}"
                    )

                current_paths = set(signatures.keys())
                expected_paths = set(expected.keys())

                added = sorted(current_paths - expected_paths)
                removed = sorted(expected_paths - current_paths)
                changed = sorted(
                    [
                        path
                        for path in current_paths.intersection(expected_paths)
                        if signatures[path] != expected[path]
                    ]
                )

                if added or removed or changed:
                    changes = "\n  ".join(
                        [p + " (added)" for p in added]
                        + [p + " (changed)" for p in changed]
                        + [p + " (removed)" for p in removed]
                    )

                    message_values = {
                        "changes": changes,
                        "name": os.path.abspath(name),
                        "paths": " \\\n     ".join(
                            [
                                os.path.abspath(rel_path)
                                for rel_path in args.header_paths
                            ]
                        ),
                        "dir": os.path.abspath(args.header_dir),
                        "signature": os.path.abspath(args.compare),
                    }

                    sys.exit(MESSAGE.format(**message_values))
        except OSError:
            sys.exit(f"could not read signature from: {args.compare}")
        with open(args.stamp, "w") as stamp:
            stamp.truncate()


def dir_signatures(header_paths, header_dir):
    for path in header_paths:
        if not os.path.exists(path):
            sys.exit(f"could not find path: {path}")

    signatures = {}
    file_paths = sorted(header_paths)

    for file_path in file_paths:
        try:
            with open(file_path, "rb") as file:
                hash = hashlib.sha1()
                while True:
                    chunk = file.read(CHUNK_SIZE)
                    if not chunk:
                        break
                    hash.update(hashlib.sha1(chunk).hexdigest().encode("utf-8"))

                relative = os.path.relpath(file_path, header_dir)
                signatures[relative] = hash.hexdigest()
        except OSError:
            sys.exit(f"could not read: {path}")

    return signatures


if __name__ == "__main__":
    main(sys.argv[0], sys.argv[1:])
