#!/usr/bin/env python3
# encoding: utf-8
# (c) 2012 Red Hat, Inc.
# Authored by Ricky Elrod
# But when it breaks, don't yell at him because that's mean.
# update hook for FI repos -> zodbot.

import os
import sys
import subprocess
import shlex
import socket

ZODBOT_SERVER = "value02.iad2.fedoraproject.org"
ZODBOT_PORT = 5050
ZODBOT_ANNOUNCE = ["ansible", "dns"]

hook = sys.argv[0]
repodir = sys.argv[1]
channel = sys.argv[2]
old = sys.argv[3]
new = sys.argv[4]
branch = sys.argv[5]

# Split on /, nuke empties from the result, use the last nonempty
# element. This lets us not care if there's a trailing slash.
repodir = [d for d in repodir.split('/') if d][-1]


def run_command(command):
    """ Run a command and return a hash with the resulting stdout/stderr."""
    escaped = shlex.split(command)
    cmd = subprocess.Popen(escaped,
                           stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE,
                           universal_newlines=True)
    stdout, stderr = cmd.communicate()
    return {"stdout": stdout, "stderr": stderr}


def construct_url(slug):
    """ Return a space-padded url to the commit.

    If and only if it is handled by pagure.  Otherwise, return an empty string.
    """

    # Our long url template.
    tmpl = "https://pagure.io/fedora-infra/{repo}/c/{slug}"

    if repodir in ZODBOT_ANNOUNCE and slug:
        return " " + tmpl.format(repo=repodir, slug=slug)
    else:
        return ""


def parse_commit(commit):
    """
    So we're given a commit in the form of:

    ---
    Ricky Elrod - test-repo:a045150 ---- add some more test files...

    A       foobar/asdf/testfile.1
    A       foobar/testfile.2
    ---

    Essentially, we rip out the first line and set it aside.
    Then all the other lines will begin with M/C/R/A/D/U.
    Replace those letters with fancy little symbols (like + for A).
    Combine them together in a list/array.
    Show the first 4 and if more exist, append '...' to the list.
    Lastly, replace the "----" in the original line above with these.
    """

    lines = commit.split("\n")
    message = lines.pop(0)
    files = []

    # extract the commit hash from the first line.
    slug = None
    try:
        slug = message.split(' -')[1].strip().split(':')[1]
    except IndexError:
        print("** Couldn't parse slug from git-rev.", message)

    # The remaining lines are files changed.
    for changed_file in filter(None, lines):
        status, filename = changed_file.split()
        if status == "M" or status == "R":
            symbol = "*"
        elif status == "C" or status == "A":
            symbol = "+"
        elif status == "D":
            symbol = "-"
        else:
            symbol = "?"

        files.append(symbol + filename)

    # Show the first 4 files changed, and if there are more, add a '...'
    # If no files were changed don't show empty [] because it looks tacky.
    fileslist = ' '.join(files[0:4])
    if len(files):
        fileslist = '[' + fileslist

        if len(files) > 4:
            fileslist += ' ...'

        fileslist += ']'
    else:
        fileslist = '-'

    padded_url = construct_url(slug)

    # Replace the ---- with the files list...
    return message.replace('----', fileslist, 1) + padded_url


# Get a list of commits to report.
cwd = os.getcwd()
if (cwd.endswith('dns') and branch == 'master') or branch == 'main':
    revs = run_command(f"git rev-list ^{old} {new}")["stdout"].split("\n")
    revs = [r for r in revs if r]
    revs.reverse()

    for commit_hash in revs:
        # Get the commit in a format that we can deal with
        commit = run_command(
            f"git show --name-status {commit_hash} --oneline "
            f"--format='%an - {repodir}:%h ---- %s'")
        parsed_commit = parse_commit(commit["stdout"])

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((ZODBOT_SERVER, ZODBOT_PORT))
        msg = f"{channel} {parsed_commit}"
        s.sendall(msg.encode('utf-8'))
        s.close()
