#!/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)
      echo "${PWD}/scripts/git_hooks${hook}"
    fi
  fi
}

function list_hooks_in_dir
{
  path="${1}"
  level="${2}"
  find --help 2>&1 | grep -- '-L' 2>/dev/null >/dev/null
  if [ $? -eq 1 ] ; then
    find "${path}/" -mindepth ${level} -maxdepth ${level} -perm -111 -type f 2>/dev/null | grep -v "^.$" | sort
  else
    find -L "${path}/" -mindepth ${level} -maxdepth ${level} -perm -111 -type f 2>/dev/null | grep -v "^.$" | sort
  fi
}

function list_hooks
{
  GITDIR=`git rev-parse --git-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 '---'
  for dir in `hook_dirs`; do
    echo "${dir}:"
    for hook in `list_hooks_in_dir "${dir}" 2`; do
      echo -n *`basename \`dirname "${hook}"\``
      echo -e "/`basename "${hook}"` - `${hook} --about`"
    done
    echo ""
  done
}

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
  for hook in `list_hooks_in_dir "${dir}" 1`
  do
    export last_run_hook="${hook} $@"
    if [ ! -z ${GIT_HOOKS_VERBOSE} ]; then
      echo -n "@@ Running hook: "
      echo -n `basename \`dirname "${hook}"\``
      echo "/`basename "${hook}"`"
    fi
    ${hook} "$@"
  done
}

function run_hook
{
  set -e
  hook=`basename "${1}"`
  if [ -z ${hook} ] ; then
    echo "run requires a hook argument"
    return 1
  fi
  shift 1
  for dir in `hook_dirs "${hook}"`; do
    if [ ! -d "${dir}" ] ; then
      continue
    fi
    run_hooks "${dir}" "$@"
  done
  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-dir`
  if [ ! $? -eq 0 ]; then
    echo "${1} must be run inside a git repository"
    return 1
  fi
  cd "${GITDIR}"
  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
}
