#!/usr/bin/env bash

#
# make-package (linux)
#
# Copyright (C) 2022 by Posit Software, PBC
#
# Unless you have received this program directly from Posit Software pursuant
# to the terms of a commercial license agreement with Posit Software, then
# this program is licensed to you under the terms of version 3 of the
# GNU Affero General Public License. This program is distributed WITHOUT
# ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
# AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
#
#

set -e

PKG_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${PKG_DIR}/../../dependencies/tools/rstudio-tools.sh"

# ensure required environment variables
if ! check_env_vars RSTUDIO_NODE_VERSION; then
	exit 1
fi

# remember cwd for later restoration
PREV_WD=$(pwd)

# raise the limit on number of open files
ulimit -n 2048

function help() {
    cat <<EOF
usage: make-package target package [clean]

Build RStudio (Electron or Server) and redistributable package for Linux.

Specify version by setting environment variables. The default is 99.9.9.

Examples
  RSTUDIO_VERSION_MAJOR=2022 RSTUDIO_VERSION_MINOR=7 RSTUDIO_VERSION_PATCH=1 RSTUDIO_VERSION_SUFFIX=-daily+321 ./make-package Server DEB

Positional Arguments
  target -- build target
    One of "Electron" or "Server"

  package
    One of "DEB" or "RPM"

Options
  clean
    Perform a clean build; default is incremental build.
EOF
exit 1
}

NPM_INSTALLED=0
install-npm-packages() {
   if [ "${NPM_INSTALLED}" = "0" ]; then
      MAKEFLAGS="" ${NPM} ci
      NPM_INSTALLED=1
   fi
}

# For a full package build the package.json file gets modified with the 
# desired build version and product name, and the build-info.ts source 
# file gets modified with details on the build (date, git-commit, etc).
# We try to put these back to their original state at the end of the 
# package build.
PACKAGE_VERSION_SET=0
set-version () {
   if [ "$RSTUDIO_TARGET" = "Electron" ]; then
      pushd ${ELECTRON_SOURCE_DIR}
      echo "ensure node-gyp installed for node ${RSTUDIO_NODE_VERSION}"
      ${NPX} node-gyp install ${RSTUDIO_NODE_VERSION}
      
      install-npm-packages

      # Set package.json info
      save-original-file package.json
      ${NPX} json -I -f package.json -e "this.version=\"$1\""
      ${NPX} json -I -f package.json -e "this.productName=\"$2\""

      # Keep a backup of build-info.ts so we can restore it
      save-original-file src/main/build-info.ts

      PACKAGE_VERSION_SET=1
      popd
   fi
}

restore-package-version () {
   if [ "${PACKAGE_VERSION_SET}" = "1" ]; then
      pushd ${ELECTRON_SOURCE_DIR}
      restore-original-file package.json
      restore-original-file src/main/build-info.ts
      PACKAGE_VERSION_SET=0
      popd
   fi
}

# ensure package.json restored on exit
on-exit () {
   restore-package-version
}

trap on-exit EXIT

PACKAGE_DIR=`pwd`
RSTUDIO_TARGET=$1
PACKAGE_TARGET=$2
CLEAN=$3

if [ "$RSTUDIO_TARGET" != "Desktop" ] && [ "$RSTUDIO_TARGET" != "Electron" ] && [ "$RSTUDIO_TARGET" != "Server" ]
then
   help
   exit 1
fi

if [ "$PACKAGE_TARGET" != "DEB" ] && [ "$PACKAGE_TARGET" != "RPM" ]
then
   help
   exit 1
fi

# set up GWT module
if [ "$RSTUDIO_TARGET" = "Desktop" ] || [ "$RSTUDIO_TARGET" == "Electron" ]; then
   GWT_MAIN_MODULE=RStudioDesktop
else
   GWT_MAIN_MODULE=RStudioServer
fi
export GWT_MAIN_MODULE

if test -z "$BUILD_DIR"
then
   # set build type( if necessary) and build dir
   if test -z "$CMAKE_BUILD_TYPE"
   then
      CMAKE_BUILD_TYPE=RelWithDebInfo
      BUILD_DIR=build-$RSTUDIO_TARGET-$PACKAGE_TARGET
   else
      BUILD_DIR=build-$RSTUDIO_TARGET-$PACKAGE_TARGET-$CMAKE_BUILD_TYPE
   fi
fi

# make build directory absolute
BUILD_DIR=$(readlink -f "$BUILD_DIR")

# clean if requested
if [ "$CLEAN" == "clean" ]
then
   # remove existing build dir
   rm -rf $BUILD_DIR

   # clean out ant build if in source tree
   if [ -d "../../src/gwt" ]; then
      cd ../../src/gwt
      ant clean
   fi
   cd $PACKAGE_DIR
fi

if [ "$RSTUDIO_TARGET" = "Desktop" ] || [ "$RSTUDIO_TARGET" == "Electron" ]
then
  INSTALL_DIR=rstudio
else
  INSTALL_DIR=rstudio-server
fi

ELECTRON_SOURCE_DIR="${PKG_DIR}/../../src/node/desktop"

# find node and npm
find-program NODE node \
   "${PKG_DIR}/../../dependencies/common/node/${RSTUDIO_NODE_VERSION}/bin" \
   "/opt/rstudio-tools/dependencies/common/node/${RSTUDIO_NODE_VERSION}/bin"
find-program NPM npm \
   "${PKG_DIR}/../../dependencies/common/node/${RSTUDIO_NODE_VERSION}/bin" \
   "/opt/rstudio-tools/dependencies/common/node/${RSTUDIO_NODE_VERSION}/bin"
find-program NPX npx \
   "${PKG_DIR}/../../dependencies/common/node/${RSTUDIO_NODE_VERSION}/bin" \
   "/opt/rstudio-tools/dependencies/common/node/${RSTUDIO_NODE_VERSION}/bin"

# put node on the path
NODE_PATH=$(dirname "${NODE}")
PATH="${NODE_PATH}:${PATH}"

# build RStudio version suffix
RSTUDIO_VERSION_ARRAY=(
   "${RSTUDIO_VERSION_MAJOR-99}"
   "${RSTUDIO_VERSION_MINOR-9}"
   "${RSTUDIO_VERSION_PATCH-9}"
)

RSTUDIO_VERSION_FULL=$(IFS="."; echo "${RSTUDIO_VERSION_ARRAY[*]}")"${RSTUDIO_VERSION_SUFFIX}"

# put version into package.json
set-version ${RSTUDIO_VERSION_FULL} rstudio

set +x

if has-program ninja || has-program ninja-build
then
   CMAKE_GENERATOR="Ninja"
   MAKEFLAGS="-w dupbuild=warn ${MAKEFLAGS}"
else
   CMAKE_GENERATOR="Unix Makefiles"
fi

: ${CMAKE_INSTALL_PREFIX="/usr/lib/${INSTALL_DIR}"}

echo "Building and packing with CMake Generator: $CMAKE_GENERATOR"

PKG_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
echo $PKG_DIR

GWT_BUILD="yes"
mkdir -p $BUILD_DIR/gwt
cd $BUILD_DIR
if test -z "$NO_REBUILD"
then
   rm -f CMakeCache.txt
   rm -rf $BUILD_DIR/_CPack_Packages
else
   GWT_BUILD="no"
fi

# show build environment when building in CI
if [ -n "${JENKINS_URL}" ]; then

   echo "Build environment:"
   printenv | sort
   echo

   echo "R version:"
   R -s -e 'sessionInfo()' || true
   R -s -e 'renv::diagnostics()' || true
   echo

fi

# if SCCACHE_ENABLED environment variable is set, use sccache
if [ -n "$SCCACHE_ENABLED" ]; then
    echo "Using sccache"
   
    if [ -n "$AWS_ACCESS_KEY_ID" ] || [ $(aws sts get-caller-identity --query "Account" --profile ${AWS_PROFILE:-sso}) -eq 14 ]; then
        echo "AWS credentials valid, using S3 build cache"
        export SCCACHE_BUCKET="rstudio-build-cache"
    else
        echo "No valid AWS SSO session, using only local build cache"
        export SCCACHE_DIR=$(pwd)/object_file_cache
        mkdir -p $SCCACHE_DIR
    fi
fi

cmake -G"${CMAKE_GENERATOR}"                           \
      -DRSTUDIO_TARGET=$RSTUDIO_TARGET                 \
      -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE             \
      -DRSTUDIO_PACKAGE_BUILD=1                        \
      -DCMAKE_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}" \
      -DGWT_BIN_DIR="$BUILD_DIR/gwt/bin"               \
      -DGWT_WWW_DIR="$BUILD_DIR/gwt/www"               \
      -DGWT_EXTRAS_DIR="$BUILD_DIR/gwt/extras"         \
      -DGWT_BUILD="$GWT_BUILD"                         \
      -DSCCACHE_ENABLED=$SCCACHE_ENABLED               \
      $PKG_DIR/../..

cmake --build . --target all -- ${MAKEFLAGS}

if [ -n "$SCCACHE_ENABLED" ]; then
   sccache --show-stats
fi

if [ "${RSTUDIO_BUILD_PACKAGE:-1}" = "1" ]; then
   cpack --verbose --debug -G "$PACKAGE_TARGET"
fi

cd "$PREV_WD"

