#!/usr/bin/env python3

"""
Check that a merge request's POM artifact version is greater than
the target branch's.
"""

import pomversion
import os
import subprocess
import click

from sys import argv, stdout, stderr
from subprocess import PIPE


def eprint(*args):
    """Prints to stderr"""
    print(*args, file=stderr)


def load_pom(commit_ish, pom_file="pom.xml"):
    """Loads the contents of a POM file.

    Parameters
    ----------
    commit_ish
        The git commit-ish to load the POM file from. If None is given
        it will load the POM file from the working directory.
    pom_file
        Path to POM file. Defaults to "pom.xml".

    Returns
    -------
    str
        The contents of the POM file from the given commit-ish.
    """

    if commit_ish is None:
        with open(pom_file, "r") as file:
            return file.read()

    command = ("git", "show", f"{commit_ish}:{pom_file}")
    process = subprocess.run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
    if process.returncode != 0:
        raise(FileNotFoundError(process.stderr.strip()))
    return process.stdout


def load_version(commit_ish, description, pom_file="pom.xml"):
    """Loads the artifact version from a POM file.

    If an error occured while loading the POM, or while extracting the
    version string, None will be returned and an appropriate error
    message will be sent to stderr.

    Parameters
    ----------
    commit_ish
        The git commit-ish to load the POM file from. If None is given
        it will load the POM file from the working directory.
    description
        Nature of the commit-ish to use in error messages. For example:
        "Source", or "Target".
    pom_file
        Path to POM file. Defaults to "pom.xml".

    Returns
    -------
    semantic_version.Version, or None
        The artifact version from the POM file as a semantic version.
    """

    try:
        pom_xml = load_pom(commit_ish, pom_file=pom_file)
        return pomversion.from_xml(pom_xml)
    except FileNotFoundError as err:
        eprint(f'Error retrieving POM file: "{err}"')
    except pomversion.InvalidVersionError as err:
        eprint(f'{description} version is invalid: "{err.version_string}"')
    except pomversion.MissingVersionError:
        eprint(f"{description} version is missing")
    return None


@click.command()
@click.argument("target_commit_ish")
@click.argument("source_commit_ish", required=False)
@click.option("--pom-file", default="pom.xml", help="Path to pom file. Defaults to pom.xml.")
@click.option("--quiet", "-q", is_flag=True, default=False, help="Only report errors.")
def mr_version_check(target_commit_ish, source_commit_ish, pom_file, quiet):
    output = open(os.devnull, "w") if quiet else stdout

    source_version = load_version(source_commit_ish, "Source", pom_file=pom_file)
    if source_version is None:
        exit(1)
    print(f"Source version: {source_version}", file=output)

    target_version = load_version(target_commit_ish, "Target", pom_file=pom_file)
    if target_version is None:
        exit(0)
    print(f"Target version: {target_version}", file=output)

    if source_version <= target_version:
        eprint("Current version must be greater than target version")
        exit(1)

if __name__ == "__main__":
    mr_version_check()
