# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv)

# Handler for git
# Usage (in package.mk):
# PKG_URL (mandatory) must point to a git repository (git://... or https://example.com/repo.git)
# PKG_VERSION (mandatory) must point to a commit SHA, e.g. a1b2c3d
# PKG_GIT_SHA (optional) full hash of git commit
# PKG_GIT_CLONE_BRANCH (optional) clone specific branch
# PKG_GIT_CLONE_SINGLE (optional) clone single branch only (set to yes)
# PKG_GIT_CLONE_DEPTH (optional) history to clone, must be a number
# PKG_GIT_SUBMODULE_DEPTH (optional) history of submodules to clone, must be a number

_get_repo_already_downloaded() {
  if [ -d "${PACKAGE}" ]; then
    (
      cd "${PACKAGE}"
      _get_repo_clean
      [ -n "$(git ls-remote . | grep -m1 HEAD | awk "/^${PKG_VERSION}/ {print \$1;}")" ] || die "ERROR: ${PACKAGE}: failed to determine git HEAD"
      [ "${PKG_URL}" = "$(git remote get-url origin)" ] || die "ERROR: ${PACKAGE}: failed to obtain URL of origin"
      [ -z "${PKG_GIT_CLONE_BRANCH}" ] && exit 0
      [ "${PKG_GIT_CLONE_BRANCH}" = "$(git branch | grep ^\* | cut -d ' ' -f2)" ] || die "ERROR: ${PACKAGE}: failed to determine current git branch"
      exit 0
    )
    return
  else
    return 1
  fi
}

_get_repo_clean() {
  git clean -fdx
  git checkout -- .
}

# Latest file already present, exit now...
_get_repo_already_downloaded && exit 0

lock_source_dir "${1}"

# Check again in case of concurrent access - if nothing needs to be downloaded, exit now...
_get_repo_already_downloaded && exit 0

# At this point, we need to download something...
build_msg "CLR_GET" "GET" "${1} (git)" "indent"

pkg_lock_status "GETPKG" "${PKG_NAME}" "unpack" "processing package repository..."

rm -f "${STAMP_URL}" "${STAMP_SHA}"

GIT_CLONE_PARAMS="--recursive --shallow-submodules --filter=tree:0"
GIT_SUBMODULE_PARAMS=""

[ -n "${PKG_GIT_CLONE_BRANCH}" ] && GIT_CLONE_PARAMS="${GIT_CLONE_PARAMS} --branch ${PKG_GIT_CLONE_BRANCH}"
[ "${PKG_GIT_CLONE_SINGLE}" = "yes" ] && GIT_CLONE_PARAMS="${GIT_CLONE_PARAMS} --single-branch"

if [ -n "${PKG_GIT_CLONE_DEPTH}" ]; then
  if [[ "${PKG_GIT_CLONE_DEPTH}" =~ ^[0-9]+$ ]]; then
    GIT_CLONE_PARAMS="${GIT_CLONE_PARAMS} --depth ${PKG_GIT_CLONE_DEPTH}"
  else
    die "ERROR: PKG_GIT_CLONE_DEPTH is not a number! (${PKG_GIT_CLONE_DEPTH})"
  fi
fi

if [ -n "${PKG_GIT_SUBMODULE_DEPTH}" ]; then
  if [[ "${PKG_GIT_SUBMODULE_DEPTH}" =~ ^[0-9]+$ ]]; then
    GIT_SUBMODULE_PARAMS="${GIT_SUBMODULE_PARAMS} --depth ${PKG_GIT_SUBMODULE_DEPTH}"
  else
    die "ERROR: PKG_GIT_SUBMODULE_DEPTH is not a number! (${PKG_GIT_SUBMODULE_DEPTH})"
  fi
fi

GIT_FOUND="no"
opwd="$(pwd)"
for d in "${SOURCES}/${1}/${1}-"* ; do
  if [ -d "${d}/.git" ]; then
    if [ "${GIT_FOUND}" = "no" ]; then
      cd "${d}"
      if [ "${PKG_URL}" = "$(git remote get-url origin)" ]; then
        if [[ -z "${PKG_GIT_CLONE_BRANCH}" ]] || [[ $(git branch | grep "^\* ${PKG_GIT_CLONE_BRANCH}$" | wc -l) -eq 1 ]]; then
          GIT_FOUND="yes"
          GIT_DIR="${d}"
          _get_repo_clean
        elif [ $(git branch | grep "^  ${PKG_GIT_CLONE_BRANCH}$" | wc -l) -eq 1 ]; then
          GIT_FOUND="yes"
          GIT_DIR="${d}"
          _get_repo_clean
          git checkout "${PKG_GIT_CLONE_BRANCH}"
        elif [ $(git branch -a | grep "^  remotes/origin/${PKG_GIT_CLONE_BRANCH}$" | wc -l) -eq 1 ]; then
          GIT_FOUND="yes"
          GIT_DIR="${d}"
          _get_repo_clean
          git checkout -b "${PKG_GIT_CLONE_BRANCH}" "origin/${PKG_GIT_CLONE_BRANCH}"
        else
          build_msg "CLR_CLEAN" "DELETE" "(${d})"
          cd "${opwd}"
          rm -rf "${d}"
        fi
        if [ "${GIT_FOUND}" = "yes" ]; then
          build_msg "CLR_GET" "GIT PULL" "${1}"

          # If there is an error with 'git pull' or updating the submodules, just reclone
          # NOTE: we run the submodule update twice if the clone already
          #       exists - but deduplicating would complicate the logic quite a lot and
          #       the second time is almost a no-op
          if ! git pull || ! git submodule update --init --recursive ${GIT_SUBMODULE_PARAMS}; then
              cd "${opwd}"
              build_msg "CLR_CLEAN" "DELETE" "(${d})"
              GIT_FOUND=NO
              rm -rf "${d}"
          fi
          cd "${opwd}"
        fi
      else
        build_msg "CLR_CLEAN" "DELETE" "(${d})"
        cd "${opwd}"
        rm -rf "${d}"
      fi
    fi
  else
    build_msg "CLR_CLEAN" "DELETE" "(${d})"
    rm -rf "${d}"
  fi
done
cd "${opwd}"

if [ "${GIT_FOUND}" = "no" ]; then
  build_msg "CLR_GET" "GIT CLONE" "${1}"
  git clone ${GIT_CLONE_PARAMS} "${PKG_URL}" "${PACKAGE}"
elif [ ! "${GIT_DIR}" = "${PACKAGE}" ]; then
  mv "${GIT_DIR}" "${PACKAGE}"
fi

( cd "${PACKAGE}"
  [ $(git log --oneline --pretty=tformat:"%H" | grep "^${PKG_VERSION}" | wc -l) -eq 1 ] || die "There is no commit '${PKG_VERSION}' on branch '$(git branch | grep ^\* | cut -d ' ' -f2)' of package '${1}'! Aborting!"
  git reset --hard "${PKG_VERSION}"
  build_msg "CLR_GET" "GIT SUBMODULE" "${1}"
  git submodule update --init --recursive ${GIT_SUBMODULE_PARAMS}
)

GIT_SHA="$(git ls-remote "${PACKAGE}" | grep -m1 HEAD | awk '{print $1;}')"

if [ -n "${PKG_GIT_SHA}" -a "${PKG_GIT_SHA}" != "${GIT_SHA}" ]; then
  build_msg "CLR_WARNING" "WARNING" "Incorrect git hash in repository: got ${GIT_SHA}, wanted ${PKG_GIT_SHA}"
fi
