#!/bin/bash
#########################################################
# 							#
# This is BashStyle-NG					#
#							#
# Licensed under GNU GENERAL PUBLIC LICENSE v3    	#
#							#
# Copyright 2007 - 2019 Christopher Bratusek		#
#							#
#########################################################

gitkit_ssh_add () {
	if check bt $(bashstyle --ini-get git_ssh_remember); then

		local git_ssh_timeout=$(bashstyle --ini-get git_ssh_timeout)
		local gitkit_file=${TMPDIR}/gitkit_time_${BASH_SESSION_PID}_${SSH_AGENT_PID}

		[ -f ${gitkit_file} ] && local gitkit_time=$(cat ${gitkit_file}) || gitkit_time=0

		eval git_ssh_keyfile=$(bashstyle --ini-get git_ssh_keyfile)

		if test ${gitkit_time} -eq 0 -o ${gitkit_time} -le $(($(date +%s) - ${git_ssh_timeout})); then
			echo -e "\n${egreen}[0] ssh-add ${git_ssh_keyfile}\n"
			ssh-add "${git_ssh_keyfile}" && echo $(date +%s) > ${gitkit_file}
		fi
	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 "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 "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 "current directory is not the root of a git repository"
		fi
	;;

	cloneuser)
		curl -s https://api.github.com/users/"${2}"/repos?per_page=200 | \
			ruby -rubygems -e 'require "json"; JSON.load(STDIN.read).each { |repo| %x[git clone #{repo["ssh_url"]} ]}'
	;;
	
	cloneorg)
		curl -s https://api.github.com/orgs/"${2}"/repos?per_page=200 | \
			ruby -rubygems -e 'require "json"; JSON.load(STDIN.read).each { |repo| %x[git clone #{repo["ssh_url"]} ]}'
	;;

	export)
		[[ ! -z "${2}" && -d .git ]] && git checkout-index --prefix="${2}"/ -a
	;;

	funmsg)
		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 "couldn't parse web location"
				;;
			esac
		else	echo "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 "current directory is not the root of a git repository"
		fi
	;;

	push)
		gitkit_ssh_add

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

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

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

	taga)
		shift

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

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

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

	tagd)
		shift

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

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

			echo -e "\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 "tag \"${in_TAG}\" does not exist!"
			exit 1
		fi

		if [ ! -z "$(git tag -l "${out_TAG}")" ]; then
			echo "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 "tag \"${TAG}\" does not exist!"
			exit 1
		fi

		if [ ! "$(git rev-parse "${COM}")" ]; then
			echo "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 "various companion functions for Git" -v "${BSNG_VERSION}" -y "${BSNG_YEAR}"\
			-o "action:|print the current action in a Git repo"\
			-o "branch:|print the current branch in a Git repo"\
			-o "bz2:|create bz2 archive from a Git repo"\
			-o "xz:|create xz archive from a Git repo"\
			-o "zip:|create zip archive from a Git repo"\
			-o "cloneuser:username|clone all repos from a GitHub user (SSH)"\
			-o "cloneorg:organization|clone all repos from a GitHub organization (SSH)"\
			-o "export:directory|export Git repo for release tarball"\
			-o "funmsg:|create funny Git commit message"\
			-o "web:|open project page using x-www-browser"\
			-o "revision:|get 6 digit revision from a Git repo"\
			-o "revno:|get traditional revision number from a Git repo"\
			-o "undelete:|undelete files accidentally deleted locally"\
			-o "push:|push/push tag upstream + push to mirror in one go"\
			-o "taga:tag [-m msg commit]|create a tag and push remote"\
			-o "tagd:tag|remove tag locally and remote"\
			-o "tagr:tag newtag|rename a tag locally and remote"\
			-o "tagc:tag newcommit|make tag point to different commit"
	;;

esac
