#!/usr/bin/env python3

import os
import json
import subprocess
import sys

if "avoid-pep8-E402-import-not-top-of-file":
    _tdir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
    sys.path.insert(0, _tdir)
    from cloudinit import version as ci_version


def tiny_p(cmd):
    stderr = subprocess.PIPE
    return subprocess.check_output(
        cmd, stderr=stderr, stdin=None, universal_newlines=True
    )


def which(program):
    # Return path of program for execution if found in path
    def is_exe(fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    _fpath, _ = os.path.split(program)
    if _fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ.get("PATH", "").split(os.pathsep):
            path = path.strip('"')
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return None


def is_gitdir(path):
    # Return boolean indicating if path is a git tree.
    git_meta = os.path.join(path, ".git")
    if os.path.isdir(git_meta):
        return True
    if os.path.exists(git_meta):
        # in a git worktree, .git is a file with 'gitdir: x'
        with open(git_meta, "rb") as fp:
            if b"gitdir:" in fp.read():
                return True
    return False


use_long = "--long" in sys.argv or os.environ.get("CI_RV_LONG")
use_tags = "--tags" in sys.argv or os.environ.get("CI_RV_TAGS")
output_json = "--json" in sys.argv

src_version = ci_version.version_string()
version_long = None

# If we're performing CI for a new release branch (which our tooling creates
# with an "upstream/" prefix), then we don't want to enforce strict version
# matching because we know it will fail.
github_ci_release_br = bool(
    os.environ.get("GITHUB_HEAD_REF", "").startswith(f"upstream/{src_version}")
)
travis_ci_release_br = bool(
    os.environ.get("TRAVIS_PULL_REQUEST_BRANCH", "").startswith("upstream/")
)
is_release_branch_ci = bool(github_ci_release_br or travis_ci_release_br)

if is_gitdir(_tdir) and which("git") and not is_release_branch_ci:
    # This cmd can be simplified to ["git", "branch", "--show-current"]
    # after bionic EOL.
    branch_name = tiny_p(["git", "rev-parse", "--abbrev-ref", "HEAD"]).strip()
    if branch_name.startswith(f"upstream/{src_version}"):
        version = src_version
        version_long = None
    else:

        flags = []
        if use_tags:
            flags = ["--tags"]
        cmd = ["git", "describe", "--abbrev=8", "--match=[0-9]*"] + flags

        try:
            version = tiny_p(cmd).strip()
        except RuntimeError:
            version = None

        if version is None or not version.startswith(src_version):
            sys.stderr.write(
                f"git describe version ({version}) differs from "
                f"cloudinit.version ({src_version})\n"
            )
            sys.stderr.write(
                "Please get the latest upstream tags.\n"
                "As an example, this can be done with the following:\n"
                "$ git remote add upstream https://git.launchpad.net/"
                "cloud-init\n"
                "$ git fetch upstream --tags\n"
            )
            sys.exit(1)

        version_long = tiny_p(cmd + ["--long"]).strip()
else:
    version = src_version
    version_long = None

# version is X.Y.Z[+xxx.gHASH]
# version_long is None or X.Y.Z-xxx-gHASH
release = version.partition("-")[0]
extra = None
commit = None
distance = None

if version_long:
    info = version_long.partition("-")[2]
    extra = "-" + info
    distance, commit = info.split("-")
    # remove the 'g' from gHASH
    commit = commit[1:]

data = {
    "release": release,
    "version": version,
    "version_long": version_long,
    "extra": extra,
    "commit": commit,
    "distance": distance,
    "is_release_branch_ci": is_release_branch_ci,
}

if output_json:
    sys.stdout.write(json.dumps(data, indent=1) + "\n")
else:
    sys.stdout.write(release + "\n")

sys.exit(0)

# vi: ts=4 expandtab
