#!/usr/bin/env python3

import os, re, subprocess, sys, yaml

if len(sys.argv) > 1 and sys.argv[1] == "--help":
    print(
        """Command: tpaexec relink clustername

Tries to repair any dangling symbolic links within a cluster directory
(e.g., deploy.yml) by making them point to the correct $TPA_DIR when
appropriate. (TPA_DIR=%s)

This command is useful if a cluster was configured on one machine and
moved to another system with TPA installed in a different location,
or to add links for new commands."""
        % os.environ.get("TPA_DIR", "<unset>")
    )
    sys.exit(0)

v = 0
if len(sys.argv) > 1 and sys.argv[1].startswith("-v"):
    v = 1

# First, we establish that we were invoked as ``tpaexec relink clusterdir`` on a
# valid cluster directory.

if "TPA_DIR" not in os.environ or not os.path.exists("./config.yml"):
    print(
        "ERROR: please invoke as 'tpaexec relink /path/to/cluster/dir'", file=sys.stderr
    )
    sys.exit(-1)

TPA_DIR = os.environ["TPA_DIR"]

modified_paths = []

# Given the name of a symbolic link and the missing target of the link, this
# function tries to point it to $TPA_DIR.

def repair_dangling_symlink(link, target):
    # We can't repair links that don't point to TPA_DIR
    if not re.findall('/(TPA|tpaexec)/', target):
        if v:
            print("%s: <ignored; unrecognised target>" % link)
        return

    new_target = re.sub('^.*/(TPA|tpaexec)/', '', target)

    for old_bdr_arch in ["CAMO2x2", "BDR-Simple"]:
        if new_target.startswith(f'architectures/{old_bdr_arch}/'):
            new_target = re.sub(old_bdr_arch, 'BDR-Always-ON', new_target)

    new_target = os.path.join(TPA_DIR, new_target)
    if os.path.exists(new_target):
        os.unlink(link)
        os.symlink(new_target, link)
        if v:
            print("%s: %s => %s" % (link, target, new_target))
    else:
        os.unlink(link)
        if v:
            print("%s: <removed>" % link)


# Now we can look for dangling symlinks somewhere under the current directory
# and try to repair them.

for subdir, dirs, files in os.walk("."):
    for f in files:
        file = os.path.join(subdir, f)
        if os.path.islink(file):
            target = os.readlink(file)
            if not os.path.exists(target):
                repair_dangling_symlink(file, target)
                modified_paths.append(file)

# Create links to any new commands or tests for this cluster's architecture.
# (The cluster configuration may have been generated long before the current
# TPA release.)

with open(r"./config.yml") as config_file:
    try:
        config = yaml.safe_load(config_file)
        architecture = config["architecture"]
    except:
        sys.exit("Failed to read 'architecture' from config.yml")

    # In theory, the architecture may return something else from
    # links_to_create(), but we ignore that possibility for now.

    for s in ["deploy.yml", "commands", "tests"]:
        target = "%s/architectures/%s/%s" % (TPA_DIR, architecture, s)

        if os.path.isfile(target) and not os.path.exists(s):
            os.symlink(target, s)
            modified_paths.append(s)
            if v:
                print("%s: %s" % (s, target))

        elif os.path.isdir(target):
            if not os.path.exists(s):
                os.mkdir(s)

            for l in os.listdir(target):
                if not os.path.exists("%s/%s" % (s, l)):
                    link = "%s/%s" % (s, l)
                    dest = "%s/%s" % (target, l)
                    os.symlink(dest, link)
                    modified_paths.append(link)
                    if v:
                        print("%s: %s" % (link, dest))

if os.path.exists(".git") and modified_paths:
    try:
        cp = subprocess.run(
            "git notes show $(git rev-list --reverse HEAD | head -1)",
            shell=True,
            capture_output=True,
            universal_newlines=True,
        )
        if cp.stdout.rstrip() == "Created by TPA":
            cp = subprocess.run(
                ["git", "add", *modified_paths],
                capture_output=True,
                universal_newlines=True,
            )
            if v:
                print(cp.stdout)
            cp = subprocess.run(
                ["git", "commit", "-m", "Relink files to the correct $TPA_DIR"],
                capture_output=True,
                universal_newlines=True,
            )
            if v:
                print(cp.stdout)
    except subprocess.CalledProcessError as cpe:
        print("Failed to git commit: %s" % cpe.stderr)
