#!/usr/bin/env bash
# Uncomment set -xv for debugging
#set -xv
{
function hook_dirs
{
  if [ ! -z "${1}" ] ; then
    hook="/${1}"
  else
    hook=""
  fi

  git rev-parse --git-dir &> /dev/null
  if [ $? -eq 0 ]; then
    if [ "$(git rev-parse --is-bare-repository)" = 'false' ]; then
      cd "$(git rev-parse --show-toplevel)" || return
      echo "${PWD}/scripts/git_hooks${hook}"
    fi
  fi
}

function list_hooks_in_dir
{
  path="${1}"
  level="${2}"
  find -L "${path}/" -mindepth "${level}" -maxdepth "${level}" \
    -perm -111 -type f -print0 2>/dev/null | sort -z
}

function list_hooks
{
  GITDIR=$(git rev-parse --git-common-dir)
  cat "${GITDIR}/hooks/pre-commit" 2> /dev/null | grep 'git-hooks' > /dev/null 2> /dev/null
  if [ $? = 0 ]; then
    echo "Git hooks ARE installed in this repository."
    echo ""
  else
    echo "Git hooks are NOT installed in this repository. (Run 'git hooks --install' to install it)"
    exit 1
  fi

  echo 'Listing Project hooks:'
  echo '---'
  dir="$(hook_dirs)"
  echo "${dir}:"
  while IFS= read -r -d '' hook; do
    echo "*$(basename "$(dirname "${hook}")")/$(basename "${hook}") - $("${hook}" --about)"
  done < <(list_hooks_in_dir "${dir}" 2)
}

function run_hooks
{
  dir="${1}"
  if [[ -z ${dir} || ! -d "${dir}" ]]; then
    echo "run_hooks requires a directory name as an argument."
    return 1
  fi
  shift 1
  while IFS= read -r -d '' hook; do
    export last_run_hook="${hook} $*"
    if [ -n "${GIT_HOOKS_VERBOSE:-}" ]; then
      echo -n "@@ Running hook: "
      echo "$(basename "$(dirname "${hook}")")/$(basename "${hook}")"
    fi
    "${hook}" "$@"
  done < <(list_hooks_in_dir "${dir}" 1)
}

function run_hook
{
  set -e
  hook=`basename "${1}"`
  if [ -z ${hook} ] ; then
    echo "run requires a hook argument"
    return 1
  fi
  shift 1
  dir="$(hook_dirs "${hook}")"
  if [ -d "${dir}" ]; then
    run_hooks "${dir}" "$@"
  fi
  set +e
}

function install_hooks_into
{
  DIR=$1
  cd "${DIR}"

  set -e
  mkdir -p hooks # some git clients do not automatically create a sample hooks directory
  mv hooks hooks.old
  set +e
  mkdir hooks
  cd hooks
  for file in applypatch-msg commit-msg post-applypatch post-checkout post-commit post-merge post-receive pre-applypatch pre-auto-gc pre-commit prepare-commit-msg pre-rebase pre-receive update pre-push
  do
    echo "${2}" > "${file}"
    chmod +x "${file}"
  done
}

function install_hooks
{
  GITDIR=$(git rev-parse --git-common-dir)
  if [ ! $? -eq 0 ]; then
    echo "${1} must be run inside a git repository"
    return 1
  fi
  cd "${GITDIR}" || return
  if [ "${1}" = "--install" ]; then
    if [ -d hooks.old ]; then
      echo "hooks.old already exists, perhaps you already installed?"
      return 0
    fi
  cmd='#!/usr/bin/env bash
if git rev-parse -q --verify MERGE_HEAD; then
  exit 0
fi
scripts/git_hooks/git-hooks run "$0" "$@"';
  install_hooks_into "${PWD}" "${cmd}"
  else
    if [ ! -d hooks.old ]; then
      echo "Error, hooks.old doesn't exists, aborting uninstall to not destroy something"
      return 1
    fi
    rm -rf hooks
    mv hooks.old hooks
  fi
}

function report_error
{
  echo "Hook failed: ${last_run_hook}"
  exit 1
}

case $1 in
  run)
    if [ ! -z "${GIT_DIR}" ]; then
      unset GIT_DIR
    fi
    shift
    trap report_error ERR
    run_hook "$@"
    ;;
  --install | --uninstall)
    install_hooks "$1"
    ;;
  -h | --help | -?)
    echo 'Git Hooks'
    echo '    A tool to manage project, user, and global Git hooks for multiple git repositories.'
    echo '    https://github.com/icefox/git-hooks'
    echo ''
    echo 'Options:'
    echo '    --install      Replace existing hooks in this repository with a call to'
    echo '                   git hooks run [hook].  Move old hooks directory to hooks.old'
    echo '    --uninstall    Remove existing hooks in this repository and rename hooks.old'
    echo '                   back to hooks'
    echo "    run <cmd>      Run the hooks for <cmd> (such as pre-commit)"
    echo "    (no arguments) Show currently installed hooks"
    ;;
  *)
    list_hooks
    ;;
esac
}
