#!/usr/bin/env python3

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

# Purpose: Publish android packages to local maven repo, but only if changed since last publish.
# Dependencies: None
# Usage: ./automation/publish_to_maven_local_if_modified.py

import os
import sys
import time
import hashlib
import argparse
from shared import run_cmd_checked, find_glean_root, fatal_err
import re

LAST_CONTENTS_HASH_FILE = ".lastAutoPublishContentsHash"

GITIGNORED_FILES_THAT_AFFECT_THE_BUILD = ["local.properties"]

parser = argparse.ArgumentParser(description="Publish android packages to local maven repo, but only if changed since last publish")
parser.parse_args()

root_dir = find_glean_root()
if str(root_dir) != os.path.abspath(os.curdir):
    fatal_err(f"This only works if run from the repo root ({root_dir!r} != {os.path.abspath(os.curdir)!r})")

# This doesn't work on "native" windows, so let's get that out of the way now.
if sys.platform.startswith("win"):
    print("NOTE: The autoPublish workflows do not work on native Windows.")
    print("You must follow the instructions in")
    print("https://mozilla.github.io/glean/dev/android/setup-android-build-environment.html")
    print("then, manually ensure that the following command has completed successfully in WSL:")
    print(sys.argv)
    print(f"(from the '{root_dir}' directory)")
    print("Then restart the build")
    # We don't want to fail here - the intention is that building, eg,
    # android-components on native Windows still works, just that it prints the
    # warning above.
    sys.exit(0)

# Calculate a hash reflecting the current state of the repo.

contents_hash = hashlib.sha256()

contents_hash.update(
    run_cmd_checked(["git", "rev-parse", "HEAD"], capture_output=True).stdout
)
contents_hash.update(b"\x00")

# Git can efficiently tell us about changes to tracked files, including
# the diff of their contents, if you give it enough "-v"s.

changes = run_cmd_checked(["git", "status", "-v", "-v"], capture_output=True).stdout
contents_hash.update(changes)
contents_hash.update(b"\x00")

# But unfortunately it can only tell us the names of untracked
# files, and it won't tell us anything about files that are in
# .gitignore but can still affect the build.

untracked_files = []

changes_lines = iter(ln.strip() for ln in changes.split(b"\n"))
try:
    ln = next(changes_lines)
    # Skip the tracked files.
    while not ln.startswith(b"Untracked files:"):
        ln = next(changes_lines)
    # Skip instructional line about using `git add`.
    ln = next(changes_lines)
    # Now we're at the list of untracked files.
    ln = next(changes_lines)
    while ln:
        untracked_files.append(ln)
        ln = next(changes_lines)
except StopIteration:
    pass

untracked_files.extend(GITIGNORED_FILES_THAT_AFFECT_THE_BUILD)

# So, we'll need to slurp the contents of such files for ourselves.

for nm in untracked_files:
    try:
        with open(nm, "rb") as f:
            contents_hash.update(f.read())
    except (FileNotFoundError, IsADirectoryError):
        pass
    contents_hash.update(b"\x00")
contents_hash.update(b"\x00")

contents_hash = contents_hash.hexdigest()

# If the contents hash has changed since last publish, re-publish.

last_contents_hash = ""
try:
    with open(LAST_CONTENTS_HASH_FILE) as f:
        last_contents_hash = f.read().strip()
except FileNotFoundError:
    pass

if contents_hash == last_contents_hash:
    print("Contents have not changed, no need to publish")
else:
    print(f"Contents have changed, publishing")
    run_cmd_checked(["./gradlew", "publishToMavenLocal", f"-Plocal={time.time_ns()}"])
    with open(LAST_CONTENTS_HASH_FILE, "w") as f:
        f.write(contents_hash)
        f.write("\n")
