#!/bin/bash
#########################################################
#                                                       #
# This is BashStyle-NG                                  #
#                                                       #
# Licensed under GNU GENERAL PUBLIC LICENSE v3          #
#                                                       #
# Copyright Christopher Roy Bratušek                    #
#                                                       #
#########################################################

. gettext.sh
export TEXTDOMAIN="bashstyle-rc"

gitkit_ssh_add () {
    if check bt "$(bashstyle --ini-get git_ssh_remember)"; then
       eval git_ssh_keyfile="$(bashstyle --ini-get git_ssh_keyfile)"
       if [[ "${git_ssh_keyfile,,}" != yubi* ]]; then
            if check P "ssh-add" "remembering SSH password"; then

                local git_ssh_timeout="$(bashstyle --ini-get git_ssh_timeout)"
                local ssh_add_keys="$(ssh-add -l | gawk '{print $3}')"

                if [[ "${ssh_add_keys}" != *${git_ssh_keyfile}* ]]; then
                    echo -e "$(eval_gettext "\n${egreen}[0] ssh-add ${git_ssh_keyfile}\n")"
                    ssh-add -t "${git_ssh_timeout}" "${git_ssh_keyfile}"
                fi
            fi
        fi
    fi
}

clone_repositories () {
    check P "wget" "'gitkit cloneorg/cloneuser'" || exit 1
    check P "xe" "'gitkit cloneorg/cloneuser'" || exit 1

    type=${1}
    host=${2}
    acc=${3}

    echo "Do you want to clone using http or ssh [default]?"
    read -r xfer

    if [[ "${host}" == "github" ]]; then
        if [[ "${xfer}" == "http" ]]; then
            curl -s https://api.github.com/"${type}"/"${acc}"/repos?per_page=100 | \
                jq -r '.[].clone_url' | xe git clone
        else
            curl -s https://api.github.com/"${type}"/"${acc}"/repos?per_page=100 | \
                jq -r '.[].ssh_url' | xe git clone
        fi
    else
        [[ ${type} == "orgs" ]] && type=groups
        if [[ "${xfer}" == "http" ]]; then
            curl -s https://gitlab.com/api/v4/"${type}"/"${acc}"/projects?per_page=100 | \
                jq -r '.[].http_url_to_repo' | xe git clone
        else
            curl -s https://gitlab.com/api/v4/"${type}"/"${acc}"/projects?per_page=100 | \
                jq -r '.[].ssh_url_to_repo' | xe git clone
        fi
    fi
}

list_repositories () {
    check P "curl" "'gitkit listorg/listuser'" || exit 1
    type=${1}
    host=${2}
    acc=${3}

    if [[ "${host}" == "github" ]]; then
        curl -s https://api.github.com/"${type}"/"${acc}"/repos?per_page=100 | \
            jq -r '.[].name'
    else
        [[ ${type} == "orgs" ]] && type=groups
        curl -s https://gitlab.com/api/v4/"${type}"/"${acc}"/projects?per_page=100 | \
            jq -r '.[].name'
    fi
}

case ${1} in

    action)
        if [[ -d .git ]]; then
            if [[ -f .git/dotest/rebasing ]]; then
                ACTION="rebase"
            elif [[ -f .git/dotest/applying ]]; then
                ACTION="apply"
            elif [[ -f .git/dotest-merge/interactive ]]; then
                ACTION="rebase -i"
            elif [[ -d .git/dotest-merge ]]; then
                ACTION="rebase -m"
            elif [[ -f .git/MERGE_HEAD ]]; then
                ACTION="merge"
            elif [[ -f .git/index.lock ]]; then
                ACTION="locked"
            elif [[ -f .git/BISECT_LOG ]]; then
                ACTION="bisect"
            else    ACTION="nothing"
            fi
            echo ${ACTION}
        else
            echo --
        fi
    ;;

    branch)
        if [[ -d .git ]]; then
            BRANCH=$(git symbolic-ref HEAD 2>/dev/null)
            echo "${BRANCH#refs/heads/}"
        else
            echo --
        fi
    ;;

    bz2)
        if [[ -d .git ]]; then
            git archive master | bzip2 -9 > "$(basename "${PWD}")".tar.bz2
        else
            echo "$(eval_gettext "current directory is not the root of a git repository")"
        fi
    ;;

    xz)
        if [[ -d .git ]]; then
            git archive master | xz -9 > "$(basename "${PWD}")".tar.xz
        else
           echo "$(eval_gettext "current directory is not the root of a git repository")"
        fi
    ;;

    zip)
        if [[ -d .git ]]; then
            git archive master --format=zip > "$(basename "${PWD}")".zip
        else
           echo "$(eval_gettext "current directory is not the root of a git repository")"
        fi
    ;;

    ghcu | ghcloneuser) clone_repositories users github "${2}" ;;
    ghco | ghcloneorg)  clone_repositories orgs github "${2}" ;;
    ghlu | ghlistuser)  list_repositories users github "${2}" ;;
    ghlo | ghlistorg)   list_repositories orgs github "${2}" ;;

    glcu | glcloneuser) clone_repositories users gitlab "${2}" ;;
    glco | glcloneorg)  clone_repositories orgs gitlab "${2}" ;;
    gllu | gllistuser)  list_repositories users gitlab "${2}" ;;
    gllo | gllistorg)   list_repositories orgs gitlab "${2}" ;;

    export)
        [[ -z "${2}" ]] && outdir="../$(basename ${PWD})_export" || outdir="${2}"
        if [[ -d .git ]]; then
            echo "exporting to: ${outdir}"
            git checkout-index --prefix="${outdir}"/ -a
        else
            echo "$(eval_gettext "current directory is not the root of a git repository")"
        fi
    ;;

    funmsg)
        check P "wget" "'gitkit funmsg'" || exit 1
        wget -qO - http://whatthecommit.com/index.txt
    ;;

    openweb | web)
        if [ -d .git ]; then
            repo_url=$(git remote -v | gawk '/origin.*fetch/{print $2}')
            case "${repo_url}" in
                git@* )
                    repo_url=$(echo "${repo_url}" | sed 's,:,/,;s,.*@,https://,')
                    x-www-browser "${repo_url}" &
                ;;
                http* )
                    x-www-browser "${repo_url}" &
                ;;
                * )
                    echo "$(eval_gettext "couldn't parse web location")"
                ;;
            esac
        else    echo "$(eval_gettext "current directory is not the root of a git repository")"
        fi
    ;;

    revision)
        if [ -d .git ]; then
            REVISION=$(git rev-parse HEAD 2>/dev/null)
            REVISION=${REVISION/HEAD/}
            echo "${REVISION:0:6}"
        else
            echo --
        fi
    ;;

    revno)
        if [[ -d .git ]]; then
            git rev-list --reverse HEAD | \
            awk "/$(git log -n 1 --pretty="format:%h")/ {print NR}"
        else
            echo --
        fi
    ;;

    undelete)
        if [ -d .git ]; then
            git checkout "$(git ls-files --deleted)"
        else
            echo "$(eval_gettext "current directory is not the root of a git repository")"
        fi
    ;;

    push)
        gitkit_ssh_add

        echo -e "$(eval_gettext "\n${eblue}[1] push to upstream\n")"
        git push

        echo -e "$(eval_gettext "\n${ecyan}[2] push tags to upstream\n")"
        git push --tag

        git_root=$(git rev-parse --show-toplevel)
        if [ -f "${git_root}/.git_mirror" ]; then
            echo -e "$(eval_gettext "\n${emagenta}[3] push to mirror\n")"
            for repo in "$(cat ${git_root}/.git_mirror)"; do
                echo -e "$(eval_gettext "${eyellow} * mirror: ${repo}\n")"
                git push --mirror "${repo}"
            done
        fi
    ;;

    taga)
        shift
        tag=${1}

        if [ -n "$(git tag -l "${tag}")" ]; then
            echo "$(eval_gettext "tag ${tag} already exists!")"
        else
            gitkit_ssh_add

            echo -e "$(eval_gettext "\n${eblue}[1] create local tag ${tag}\n")"
            git tag -a "${@}" || exit 1

            echo -e "$(eval_gettext "\n${ecyan}[2] push tag to remote\n")"
            git push --tag
        fi
    ;;

    tagd)
        shift
        tag=${1}

        if [ -z "$(git tag -l "${1}")" ]; then
            echo "$(eval_gettext "tag ${tag} does not exist!")"
        else
            gitkit_ssh_add

            echo -e "$(eval_gettext "\n${eblue}[1] remove local tag ${tag}\n")"
            git tag -d "${1}" || exit 1

            echo -e "$(eval_gettext "\n${ecyan}[2] remove remote tag\n")"
            git push origin :refs/tags/"${1}"
        fi
    ;;

    tagr)
        shift
        in_TAG="${1}"
        out_TAG="${2}"

        if [ -z "$(git tag -l "${in_TAG}")" ]; then
            echo "$(eval_gettext "tag ${in_TAG} does not exist!")"
            exit 1
        fi

        if [ -n "$(git tag -l "${out_TAG}")" ]; then
            echo "$(eval_gettext "tag ${out_TAG} already exists!")"
            exit 1
        fi

        TAG_msg="$(git tag -n1 "${in_TAG}" | gawk '{sub($1 FS,"")}1')"
        TAG_commit="$(git rev-list -n1 "${in_TAG}")"

        gitkit tagd "${in_TAG}"
        gitkit taga "${out_TAG}" -m "${TAG_msg}" "${TAG_commit}"
    ;;

    tagc)
        shift
        TAG="${1}"
        COM="${2}"

        if [ -z "$(git tag -l "${TAG}")" ]; then
            echo "$(eval_gettext "tag ${TAG} does not exist!")"
            exit 1
        fi

        if [ ! "$(git rev-parse "${COM}")" ]; then
            echo "$(eval_gettext "commit ${COM} does not exist!")"
            exit 1
        fi

        TAG_msg="$(git tag -n1 "${in_TAG}" | gawk '{sub($1 FS,"")}1')"

        gitkit tagd "${TAG}"
        gitkit taga "${TAG}" -m "${TAG_msg}" "${COM}"
    ;;

    *)
        bashstyle-help -a "Christopher Roy Bratusek" -e "nano@jpberlin.de" -h "https://www.nanolx.org/"\
            -l "GNU GPL v3" -n "gitkit" -s "$(eval_gettext "various companion functions for Git")"\
            -v "${BSNG_VERSION}" -y "${BSNG_YEAR}"\
            -o "$(eval_gettext "action:|print the current action in a Git repo")"\
            -o "$(eval_gettext "branch:|print the current branch in a Git repo")"\
            -o "$(eval_gettext "bz2:|create bz2 archive from a Git repo")"\
            -o "$(eval_gettext "xz:|create xz archive from a Git repo")"\
            -o "$(eval_gettext "zip:|create zip archive from a Git repo")"\
            -o "$(eval_gettext "ghcloneuser:username|clone all repos from a GitHub user")"\
            -o "$(eval_gettext "ghcloneorg:organization|clone all repos from a GitHub organization")"\
            -o "$(eval_gettext "ghlistuser:username|list all repos from a GitHub user")"\
            -o "$(eval_gettext "ghlistorg:organization|list all repos from a GitHub organization")"\
            -o "$(eval_gettext "glcloneuser:username|clone all repos from a GitLab user")"\
            -o "$(eval_gettext "glcloneorg:organization|clone all repos from a GitLab organization")"\
            -o "$(eval_gettext "gllistuser:username|list all repos from a GitLab user")"\
            -o "$(eval_gettext "gllistorg:organization|list all repos from a GitLab organization")"\
            -o "$(eval_gettext "export:directory|export Git repo for release tarball")"\
            -o "$(eval_gettext "funmsg:|create funny Git commit message")"\
            -o "$(eval_gettext "web:|open project page using x-www-browser")"\
            -o "$(eval_gettext "revision:|get 6 digit revision from a Git repo")"\
            -o "$(eval_gettext "revno:|get traditional revision number from a Git repo")"\
            -o "$(eval_gettext "undelete:|undelete files accidentally deleted locally")"\
            -o "$(eval_gettext "push:|push/push tag upstream + push to mirror in one go")"\
            -o "$(eval_gettext "taga:tag [-m msg commit]|create a tag and push remote")"\
            -o "$(eval_gettext "tagd:tag|remove tag locally and remote")"\
            -o "$(eval_gettext "tagr:tag newtag|rename a tag locally and remote")"\
            -o "$(eval_gettext "tagc:tag newcommit|make tag point to different commit")"
    ;;
esac
