#!/bin/bash

# Currently the script is tested only on Linux and only in remote mode of SubGit

GIT="git"

function abs_path() {
  pushd "$PWD" &>/dev/null

  local file="${1%/}"
  local result="$2"
  local file_basename="${file##*/}"
  local file_parent="${file%$file_basename}"
  if [ "x$file_parent" != "x" ]; then
    cd "$file_parent"
  fi
  local abs_file_parent="$(pwd -P)"
  local abs_file_parent_with_basename="$abs_file_parent/$file_basename"
  abs_file="${abs_file_parent_with_basename}"
  eval $result="'$abs_file'"

  popd &>/dev/null
}

cygwin=false
os400=false
darwin=false
case "`uname`" in
CYGWIN*) cygwin=true;;
OS400*) os400=true;;
Darwin*) darwin=true;;
esac

PRG="$0"
while [ -h "$PRG" ]; do
  ls=`ls -ld "$PRG"`
  link=`expr "$ls" : '.*-> \(.*\)$'`
  if expr "$link" : '/.*' > /dev/null; then
    PRG="$link"
  else
    PRG=`dirname "$PRG"`/"$link"
  fi
done

abs_path "$(dirname "$PRG")" SCRIPT_DIR
abs_path "$(dirname "$SCRIPT_DIR")" GIT_REPOS

SUBGIT_INSTALLATION="${GIT_REPOS%/.}"

export GIT_DIR="$SUBGIT_INSTALLATION"
SUBGIT_CONFIG_FILE="$SUBGIT_INSTALLATION/subgit/config"

SVN_URL="$($GIT config -f "$SUBGIT_CONFIG_FILE" --get svn.url)"
if [ x$SVN_URL = x ] ; then
  echo "This script works only in remote mode of SubGit."
  echo "Please, contact support@subgit.com if you want a hook for local mode."
  exit 1
fi

RELATIVE_AUTHORS_PATH="$($GIT config -f "$SUBGIT_CONFIG_FILE" --get core.authorsFile)"
if [ x"$RELATIVE_AUTHORS_PATH" != x -a "${RELATIVE_AUTHORS_PATH:0:1}" = "/" ] ; then
  AUTHORS_PATH="$RELATIVE_AUTHORS_PATH"
else
  AUTHORS_PATH="$SUBGIT_INSTALLATION/$RELATIVE_AUTHORS_PATH"
fi

REMOTE_REFS="$($GIT show-ref | awk '$2 ~ /^refs\/svn\/root/{print "^"$2}')"

NEW_COMMITS=""
NEW_COMMITS_AUTHORS_EMAILS=""
NOT_FOUND_AUTHORS_EMAILS=""

append_new_commits() {
  OLD_SHA1="$1"
  NEW_SHA1="$2"
  BRANCH="$3"
  
  if [ x$OLD_SHA1 != x0000000000000000000000000000000000000000 -a x$NEW_SHA1 != x0000000000000000000000000000000000000000 ] ; then
    NEW_COMMITS="$($GIT rev-list $OLD_SHA1..$NEW_SHA1 --not $REMOTE_REFS)"$'\n'"$NEW_COMMITS"
  elif [ x$NEW_SHA1 != x0000000000000000000000000000000000000000 ] ; then
    NEW_COMMITS="$($GIT rev-list $NEW_SHA1 --not $REMOTE_REFS)"$'\n'"$NEW_COMMITS"
  fi
}

check_svn_author_existence() {
  AUTHOR_EMAIL=$@
  IFS="/" read -r AUTHOR EMAIL <<< "$AUTHOR_EMAIL"
  
  if [ -x "$AUTHORS_PATH" ] ; then
    SVN_AUTHOR=$(echo $AUTHOR$'\n'$EMAIL | $AUTHORS_PATH)
    EXIT_CODE="$?"
    
    if [ x$EXIT_CODE != x0 -o x"$SVN_AUTHOR" == x ] ; then
      NOT_FOUND_AUTHORS_EMAILS="$NOT_FOUND_AUTHORS_EMAILS"$'\n'"$AUTHOR <$EMAIL>"
    fi
  elif [ -f "$AUTHORS_PATH" ] ; then
    if [ x"$EMAIL" != x ] ; then
      sed -e 's/^#.*$//g' $AUTHORS_PATH | grep -xq '^\s*.*\s*=.*<'"$EMAIL"'>\s*$'
      EXIT_CODE="$?"
      if [ x$EXIT_CODE != x0 ] ; then
        NOT_FOUND_AUTHORS_EMAILS="$NOT_FOUND_AUTHORS_EMAILS"$'\n'"$AUTHOR <$EMAIL>"
      fi
    fi
  else
    NOT_FOUND_AUTHORS_EMAILS="$NOT_FOUND_AUTHORS_EMAILS"$'\n'"$AUTHOR <$EMAIL>"
  fi
}

while read line; do
  append_new_commits $line
done

NEW_COMMITS="$(echo "$NEW_COMMITS" | sort | uniq | grep -v ^$)"

for COMMIT in $NEW_COMMITS ; do
  AUTHOR_EMAIL=$($GIT log -n 1 --format="%an/%ae" $COMMIT)
  NEW_COMMITS_AUTHORS_EMAILS="$NEW_COMMITS_AUTHORS_EMAILS"$'\n'$AUTHOR_EMAIL
done

NEW_COMMITS_AUTHORS_EMAILS="$(echo "$NEW_COMMITS_AUTHORS_EMAILS" | sort | uniq | grep -v ^$)"

while IFS= read -r AUTHOR_EMAIL ; do
  check_svn_author_existence $AUTHOR_EMAIL
done <<< "$NEW_COMMITS_AUTHORS_EMAILS"

if [ x"$NOT_FOUND_AUTHORS_EMAILS" == x ] ; then
  exit 0
else
  echo "Unable to find the following authors of commits being pushed"
  echo "using $AUTHORS_PATH file:"
  echo ""
  
  while IFS= read -r AUTHOR_EMAIL ; do
    echo $'\t'"$AUTHOR_EMAIL"
  done <<< "$NOT_FOUND_AUTHORS_EMAILS"

  echo ""
  echo "Edit $AUTHORS_PATH file on Git server"
  echo "to provide corresponding SVN author(s) and retry pushing."
  
  exit 1
fi
