#!/usr/bin/env bash

#
# Defense-in-depth for magit (the .git/hooks wrapper unsets it too); ensures
# hooks invoked from emacs/magit behave the same as on the CLI.
# https://magit.vc/manual/magit/My-Git-hooks-work-on-the-command_002dline-but-not-inside-Magit.html
#
unset GIT_LITERAL_PATHSPECS

HAS_NODE=`which node 2> /dev/null || which nodejs 2> /dev/null || which iojs 2> /dev/null`

#
# There are some issues with Source Tree because paths are not set correctly for
# the given environment. Sourcing the bash_profile seems to resolve this for bash users,
# sourcing the zshrc for zshell users.
#
# https://answers.atlassian.com/questions/140339/sourcetree-hook-failing-because-paths-don-t-seem-to-be-set-correctly
#
function source_home_file {
  file="$HOME/$1"
  [[ -f "${file}" ]] && source "${file}"
}

if [[ -z "$HAS_NODE" ]]; then
  source_home_file ".bash_profile" || source_home_file ".zshrc" || source_home_file ".bashrc" || true
fi

NODE=`which node 2> /dev/null`
NODEJS=`which nodejs 2> /dev/null`
IOJS=`which iojs 2> /dev/null`
LOCAL="/usr/local/bin/node"
BINARY=

#
# Figure out which binary we need to use for our script execution.
#
if [[ -n "$NODE" ]]; then
  BINARY="$NODE"
elif [[ -n "$NODEJS" ]]; then
  BINARY="$NODEJS"
elif [[ -n "$IOJS" ]]; then
  BINARY="$IOJS"
elif [[ -x "$LOCAL" ]]; then
  BINARY="$LOCAL"
fi

#
# Run from the repository root so `require.resolve('pre-commit')` works for Yarn PnP,
# and GUI git clients that invoke hooks with an unexpected cwd still resolve deps.
#
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || REPO_ROOT=""
if [[ -n "$REPO_ROOT" ]]; then
  cd "$REPO_ROOT" || exit 1
fi

#
# Resolve the entry point of the `pre-commit` package via Node so we work for
# Yarn Plug'n'Play, hoisted, and nested layouts. If the package cannot be
# resolved (e.g. the user switched to a branch with no `node_modules`, or
# uninstalled `pre-commit`) skip the hook with exit 0 instead of failing the
# commit -- a missing dev dependency must not block work.
#
RESOLVED=
RESOLVE_RC=1
if [[ -n "$BINARY" ]]; then
  RESOLVED="$("$BINARY" -e "try { console.log(require.resolve('pre-commit')); } catch (e) { process.exit(2); }" 2>/dev/null)"
  RESOLVE_RC=$?
fi

#
# Add --dry-run cli flag support so we can execute this hook without side effects
# and see if it works in the current environment
#
if [[ $* == *--dry-run* ]]; then
  if [[ -z "$BINARY" ]] || [[ "$RESOLVE_RC" -ne 0 ]] || [[ -z "$RESOLVED" ]]; then
    exit 1
  fi
else
  if [[ "$RESOLVE_RC" -ne 0 ]] || [[ -z "$RESOLVED" ]]; then
    echo "pre-commit: 'pre-commit' package is not installed; skipping hooks (run \`npm install\` to re-enable)." >&2
    exit 0
  fi
  exec "$BINARY" "$RESOLVED"
fi
