#!/usr/bin/env bash

set -xeu -o pipefail

SRC_ROOT="$( cd "$(dirname "$0")" ; pwd -P)/.."
PYTORCH_ROOT=${PYTORCH_ROOT:-$SRC_ROOT/externals/pytorch}
PYTORCH_INSTALL_PATH=${PYTORCH_INSTALL_PATH:-$SRC_ROOT/libtorch}
TORCH_MLIR_SRC_PYTORCH_REPO="${TORCH_MLIR_SRC_PYTORCH_REPO:-pytorch/pytorch}"
TORCH_MLIR_SRC_PYTORCH_BRANCH="${TORCH_MLIR_SRC_PYTORCH_BRANCH:-master}"
TM_PYTORCH_INSTALL_WITHOUT_REBUILD="${TM_PYTORCH_INSTALL_WITHOUT_REBUILD:-false}"
PT_C_COMPILER="${PT_C_COMPILER:-clang}"
PT_CXX_COMPILER="${PT_CXX_COMPILER:-clang++}"
CMAKE_OSX_ARCHITECTURES="${CMAKE_OSX_ARCHITECTURES:-x86_64}"
MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-12.0}"
WHEELHOUSE="${WHEELHOUSE:-$SRC_ROOT/build_tools/python_deploy/wheelhouse}"
PYTHON_BIN="${TORCH_MLIR_PYTHON_VERSION:-python3}"
PIP_BIN="${TORCH_MLIR_PIP_VERSION:-pip3}"
CMAKE_C_COMPILER_LAUNCHER="${CMAKE_C_COMPILER_LAUNCHER:-""}"
CMAKE_CXX_COMPILER_LAUNCHER="${CMAKE_CXX_COMPILER_LAUNCHER:-""}"

Red='\033[0;31m'
Green='\033[0;32m'
Yellow='\033[1;33m'
NC='\033[0m'

echo "SRC_ROOT=${SRC_ROOT}"
echo "PYTORCH_ROOT=${PYTORCH_ROOT}"
echo "TORCH_MLIR_SRC_PYTORCH_REPO=${TORCH_MLIR_SRC_PYTORCH_REPO}"
echo "TORCH_MLIR_SRC_PYTORCH_BRANCH=${TORCH_MLIR_SRC_PYTORCH_BRANCH}"
echo "MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET}"
echo "CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}"

export CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
export MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET}
export CMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER}
export CMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER}

retry () {
  "$@" || (sleep 1 && "$@") || (sleep 2 && "$@") || (sleep 4 && "$@") || (sleep 8 && "$@")
}

install_requirements() {
  ${PIP_BIN} install -qr $PYTORCH_ROOT/requirements.txt
  ${PIP_BIN} list
}

checkout_pytorch() {
  if [[ ! -d "$PYTORCH_ROOT" ]]; then
    # ${TORCH_MLIR_SRC_PYTORCH_BRANCH} could be a branch name or a commit hash.
    # Although `git clone` can accept a branch name, the same command does not
    # accept a commit hash, so we instead use `git fetch`.  The alternative is
    # to clone the entire repository and then `git checkout` the requested
    # branch or commit hash, but that's too expensive.
    mkdir "${PYTORCH_ROOT}"
    cd "${PYTORCH_ROOT}"
    git init
    git remote add origin "https://github.com/${TORCH_MLIR_SRC_PYTORCH_REPO}"
    git fetch --depth=1 origin "${TORCH_MLIR_SRC_PYTORCH_BRANCH}"
    git reset --hard FETCH_HEAD
  else
    cd "${PYTORCH_ROOT}"
    git fetch --depth=1 origin "${TORCH_MLIR_SRC_PYTORCH_BRANCH}"
    git reset --hard FETCH_HEAD
  fi
  git clean -df
  git submodule update --init --depth 1 --recursive
}

build_pytorch() {
  cd "$PYTORCH_ROOT"
  # Uncomment the next line if you want to iterate on source builds
  # ${PYTHON_BIN} setup.py clean
  rm -rf "${WHEELHOUSE:?}"/*

  if [[ -z "${MAX_JOBS:-""}" ]]; then
    if [[ "$(uname)" == 'Darwin' ]]; then
      MAX_JOBS=$(sysctl -n hw.ncpu)
    else
      MAX_JOBS=$(nproc)
    fi
  fi

  BUILD_SHARED_LIBS=ON \
  BUILD_CAFFE2_OPS=OFF \
  INTERN_BUILD_ATEN_OPS=OFF \
  ATEN_NO_TEST=OFF \
  USE_LITE_INTERPRETER_PROFILER=OFF \
  BUILD_TEST=OFF \
  GLIBCXX_USE_CXX11_ABI=1 \
  CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} \
  MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} \
  INTERN_BUILD_ATEN_OPS=OFF \
  INTERN_DISABLE_ONNX=ON \
  INTERN_USE_EIGEN_BLAS=ON \
  MAX_JOBS=${MAX_JOBS} \
  ONNX_ML=OFF \
  USE_BREAKPAD=OFF \
  USE_CUDA=OFF \
  USE_ITT=OFF \
  USE_DISTRIBUTED=OFF \
  USE_EIGEN_FOR_BLAS=OFF \
  USE_FBGEMM=ON \
  USE_GLOO=OFF \
  USE_KINETO=ON \
  USE_MKL=OFF \
  USE_MKLDNN=OFF \
  USE_MPS=OFF \
  USE_NCCL=OFF \
  USE_NNPACK=OFF \
  USE_OBSERVERS=OFF \
  USE_OPENMP=OFF \
  USE_PYTORCH_QNNPACK=ON \
  USE_QNNPACK=OFF \
  USE_XNNPACK=OFF \
  USE_PRECOMPILED_HEADERS=1 \
  ${PYTHON_BIN} setup.py  bdist_wheel -d "$WHEELHOUSE"
}

package_pytorch() {
  mkdir -p libtorch
  if [[ -d "libtorch/lib" ]]; then
    rm -rf libtorch/{lib,bin,include,share}
  fi

  # Copy over all of the cmake files
  mv build/lib*/torch/share     libtorch/
  mv build/lib*/torch/include   libtorch/
  mv build/lib*/torch/lib       libtorch/
  # Copy over all lib files
  mv build/lib/*                libtorch/lib/
  # Copy over all include files
  mv build/include/*            libtorch/include/

  (pushd "$PYTORCH_ROOT" && git rev-parse HEAD) > libtorch/build-hash
  echo "Installing libtorch in ${PYTORCH_ROOT}/../../"
  echo "deleting old ${PYTORCH_ROOT}/../../libtorch"
  rm -rf "${PYTORCH_ROOT}"/../../libtorch
  mv libtorch "${PYTORCH_ROOT}"/../../
}

install_pytorch() {
  echo "pip installing Pytorch.."
  ${PIP_BIN} install  --force-reinstall $WHEELHOUSE/*
}

unpack_pytorch() {
  PYTHON_SITE=`${PYTHON_BIN} -c 'import sysconfig; print(sysconfig.get_paths()["purelib"])'`
  echo "wheel unpacking Pytorch..into ${PYTHON_SITE}"
  wheel unpack -d "$WHEELHOUSE"/unpack_tmp "$WHEELHOUSE"/*.whl
  mv "$WHEELHOUSE"/unpack_tmp/* "$PYTHON_SITE"/
}

#main
echo "Building libtorch from source"
wheel_exists=true
compgen -G "$WHEELHOUSE/*.whl" > /dev/null || wheel_exists=false
if [[ $TM_PYTORCH_INSTALL_WITHOUT_REBUILD != "true" || ${wheel_exists} == "false" ]]; then
  checkout_pytorch
  install_requirements
  build_pytorch
  package_pytorch
fi
if [[ $CMAKE_OSX_ARCHITECTURES = "arm64" ]]; then
  echo "${Yellow} Cross compiling for arm64 so unpacking PyTorch wheel for libs${NC}"
  unpack_pytorch
else
  echo "${Green} Installing the built PyTorch wheel ${NC}"
  install_pytorch
fi
