#!/usr/bin/env python3
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""A git pre-commit hook to drop staged gitlink changes.

To bypass this hook, set SKIP_GITLINK_PRECOMMIT=1.
"""

import os
import sys

ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT_DIR)

import git_common  # noqa: E402
from gclient_eval import SYNC  # noqa: E402

SKIP_VAR = "SKIP_GITLINK_PRECOMMIT"
TESTING_ANSWER = "TESTING_ANSWER"


def main():
    if os.getenv(SKIP_VAR) == "1":
        print(f"{SKIP_VAR} is set. Committing gitlinks, if any.")
        exit(0)

    has_deps_diff = False
    staged_gitlinks = []
    diff = git_common.run(
        "diff-index", "--cached", "--ignore-submodules=dirty", "HEAD"
    )
    for line in diff.splitlines():
        path = line.split()[-1]
        if path == "DEPS":
            has_deps_diff = True
            continue
        if line.startswith(":160000 160000"):
            staged_gitlinks.append(path)

    if not staged_gitlinks or has_deps_diff:
        exit(0)

    # There are staged gitlinks and DEPS wasn't changed. Get git_dependencies
    # migration state in DEPS.
    state = None
    try:
        with open("DEPS", "r") as f:
            for l in f.readlines():  # noqa: E741
                if l.startswith("git_dependencies"):
                    state = l.split()[-1].strip(" \"'")
                    break
    except OSError:
        # Don't abort the commit if DEPS wasn't found.
        exit(0)

    if state != SYNC:
        # DEPS only has to be in sync with gitlinks when state is SYNC.
        exit(0)

    prompt = (
        f"Found no change to DEPS, but found staged gitlink(s) in diff:\n{diff}\n"
        'Press Enter/Return if you intended to include them or "n" to unstage '
        "(exclude from commit) the gitlink(s): "
    )
    print(prompt)

    if os.getenv(TESTING_ANSWER) is not None:
        answer = os.getenv(TESTING_ANSWER)
    else:
        try:
            sys.stdin = open("/dev/tty", "r")
        except (FileNotFoundError, OSError):
            try:
                sys.stdin = open("CON")
            except:  # noqa: E722
                print(
                    "Unable to acquire input handle, proceeding without modifications"
                )
                exit(0)
        answer = input()

    disable_msg = f"To disable this hook, set {SKIP_VAR}=1"
    if answer.lower() == "n":
        print(
            f"\nUnstaging {len(staged_gitlinks)} staged gitlink(s) found in diff"
        )
        git_common.run("restore", "--staged", "--", *staged_gitlinks)
        if len(staged_gitlinks) == len(diff.splitlines()):
            print(
                "\nFound no changes after unstaging gitlinks, aborting commit."
            )
            print(disable_msg)
            exit(1)

    print(disable_msg)


if __name__ == "__main__":
    main()
