# TODO(michaelpg): Dedupe common functionality with the Chrome installer. See
# https://crbug.com/820270.

# Shows the output of a given command only on failure, or when VERBOSE is set.
log_cmd() {
  if [ "${VERBOSE:-}" ]; then
    "$@"
  else
    # Record $- into a separate variable because it gets reset in the subshell.
    FORWARD_SHELL_OPTS=$-
    ERREXIT=$(echo ${FORWARD_SHELL_OPTS} | grep -o e || true)
    set +${ERREXIT}
    CMD_OUTPUT=$("$@" 2>&1)
    ERRCODE=$?
    set -${ERREXIT}
    if [ ${ERRCODE} -ne 0 ]; then
      echo "$@"
      echo "${CMD_OUTPUT}"
      if [ ${ERREXIT} ]; then
        exit ${ERRCODE}
      fi
    fi
  fi
}

# Recursively replace @@include@@ template variables with the referenced file,
# and write the resulting text to stdout.
process_template_includes() {
  INCSTACK+="$1->"
  # Includes are relative to the file that does the include.
  INCDIR=$(dirname $1)
  # Clear IFS so 'read' doesn't trim whitespace
  local OLDIFS="$IFS"
  IFS=''
  while read -r LINE
  do
    INCLINE=$(sed -e '/^[[:space:]]*@@include@@/!d' <<<$LINE)
    if [ -n "$INCLINE" ]; then
      INCFILE=$(echo $INCLINE | sed -e "s#@@include@@\(.*\)#\1#")
      # Simple filename match to detect cyclic includes.
      CYCLE=$(sed -e "\#$INCFILE#"'!d' <<<$INCSTACK)
      if [ "$CYCLE" ]; then
        echo "ERROR: Possible cyclic include detected." 1>&2
        echo "$INCSTACK$INCFILE" 1>&2
        exit 1
      fi
      if [ ! -r "$INCDIR/$INCFILE" ]; then
        echo "ERROR: Couldn't read include file: $INCDIR/$INCFILE" 1>&2
        exit 1
      fi
      process_template_includes "$INCDIR/$INCFILE"
    else
      echo "$LINE"
    fi
  done < "$1"
  IFS="$OLDIFS"
  INCSTACK=${INCSTACK%"$1->"}
}

# Replace template variables (@@VARNAME@@) in the given template file. If a
# second argument is given, save the processed text to that filename, otherwise
# modify the template file in place.
process_template() (
  # Don't worry if some of these substitution variables aren't set.
  # Note that this function is run in a sub-shell so we don't leak this
  # setting, since we still want unbound variables to be an error elsewhere.
  set +u

  local TMPLIN="$1"
  if [ -z "$2" ]; then
    local TMPLOUT="$TMPLIN"
  else
    local TMPLOUT="$2"
  fi
  # Process includes first so included text also gets substitutions.
  TMPLINCL="$(process_template_includes "$TMPLIN")"
  sed \
    -e "s#@@PACKAGE@@#${PACKAGE}#g" \
    -e "s#@@PACKAGE_ORIG@@#${PACKAGE_ORIG}#g" \
    -e "s#@@PACKAGE_FILENAME@@#${PACKAGE_FILENAME}#g" \
    -e "s#@@PROGNAME@@#${PROGNAME}#g" \
    -e "s#@@CHANNEL@@#${CHANNEL}#g" \
    -e "s#@@COMPANY_FULLNAME@@#${COMPANY_FULLNAME}#g" \
    -e "s#@@VERSION@@#${VERSION}#g" \
    -e "s#@@PACKAGE_RELEASE@@#${PACKAGE_RELEASE}#g" \
    -e "s#@@VERSIONFULL@@#${VERSIONFULL}#g" \
    -e "s#@@INSTALLDIR@@#${INSTALLDIR}#g" \
    -e "s#@@BUILDDIR@@#${BUILDDIR}#g" \
    -e "s#@@STAGEDIR@@#${STAGEDIR}#g" \
    -e "s#@@SCRIPTDIR@@#${SCRIPTDIR}#g" \
    -e "s#@@MENUNAME@@#${MENUNAME}#g" \
    -e "s#@@PRODUCTURL@@#${PRODUCTURL}#g" \
    -e "s#@@PREDEPENDS@@#${PREDEPENDS}#g" \
    -e "s#@@DEPENDS@@#${DEPENDS}#g" \
    -e "s#@@RECOMMENDS@@#${RECOMMENDS}#g" \
    -e "s#@@PROVIDES@@#${PROVIDES}#g" \
    -e "s#@@ARCHITECTURE@@#${ARCHITECTURE}#g" \
    -e "s#@@MAINTNAME@@#${MAINTNAME}#g" \
    -e "s#@@MAINTMAIL@@#${MAINTMAIL}#g" \
    -e "s#@@REPOCONFIG@@#${REPOCONFIG}#g" \
    -e "s#@@REPOCONFIGREGEX@@#${REPOCONFIGREGEX}#g" \
    -e "s#@@SHORTDESC@@#${SHORTDESC}#g" \
    -e "s#@@FULLDESC@@#${FULLDESC}#g" \
    -e "s#@@USR_BIN_SYMLINK_NAME@@#${USR_BIN_SYMLINK_NAME:-}#g" \
    -e "s#@@LOGO_RESOURCES_PNG@@#${LOGO_RESOURCES_PNG}#g" \
    -e "s#@@LOGO_RESOURCE_XPM@@#${LOGO_RESOURCE_XPM}#g" \
    > "$TMPLOUT" <<< "$TMPLINCL"
)

# Setup the installation directory hierachy in the package staging area.
prep_staging_common() {
  install -m 755 -d "${STAGEDIR}/${INSTALLDIR}" \
    "${STAGEDIR}/usr/bin"
}

get_version_info() {
  source "${BUILDDIR}/app_shell_installer/version.txt"
  VERSION="${MAJOR}.${MINOR}.${BUILD}.${PATCH}"
  # TODO(phajdan.jr): Provide a mechanism to pass a different package
  # release number if needed. The meaning of it is to bump it for
  # packaging-only changes while the underlying software has the same version.
  # This corresponds to the Release field in RPM spec files and debian_revision
  # component of the Version field for DEB control file.
  # Generally with Chrome's fast release cycle it'd be more hassle to try
  # to bump this number between releases.
  PACKAGE_RELEASE="1"
}

stage_install_common() {
  log_cmd echo "Staging common install files in '${STAGEDIR}'..."

  # Note: Changes here may also need to be applied to ChromeOS's
  # chromite/lib/chrome_util.py.

  # Note: This only supports static binaries and does not work when the GN
  # is_component_build flag is true.

  # app
  STRIPPEDFILE="${BUILDDIR}/${PROGNAME}.stripped"
  install -m 755 "${STRIPPEDFILE}" "${STAGEDIR}/${INSTALLDIR}/${PROGNAME}"

  # resources
  install -m 644 \
    "${BUILDDIR}/extensions_shell_and_test.pak" \
    "${STAGEDIR}/${INSTALLDIR}/"

  # ICU data file; Necessary when the GN icu_use_data_file flag is true.
  install -m 644 "${BUILDDIR}/icudtl.dat" "${STAGEDIR}/${INSTALLDIR}/"

  # V8 snapshot files; Necessary when the GN v8_use_external_startup_data flag 
  # is true.
  if [ -f "${BUILDDIR}/natives_blob.bin" ]; then
    install -m 644 "${BUILDDIR}/natives_blob.bin" "${STAGEDIR}/${INSTALLDIR}/"
    # Use v8_context_snapshot.bin instead of snapshot_blob.bin if it is available.
    # TODO(crbug.com/764576): Unship snapshot_blob.bin on ChromeOS and drop this branch
    if [ -f "${BUILDDIR}/v8_context_snapshot.bin" ]; then
      install -m 644 "${BUILDDIR}/v8_context_snapshot.bin" "${STAGEDIR}/${INSTALLDIR}/"
    else
      install -m 644 "${BUILDDIR}/snapshot_blob.bin" "${STAGEDIR}/${INSTALLDIR}/"
    fi
  fi

  # ANGLE
  if [ "${CHANNEL}" != "stable" ]; then
    install -m 644 "${BUILDDIR}/libGLESv2.so" "${STAGEDIR}/${INSTALLDIR}/"
    install -m 644 "${BUILDDIR}/libEGL.so" "${STAGEDIR}/${INSTALLDIR}/"
  fi

  # SwiftShader
  if [ -f "${BUILDDIR}/swiftshader/libEGL.so" ]; then
    install -m 755 -d "${STAGEDIR}/${INSTALLDIR}/swiftshader/"
    install -m 644 "${BUILDDIR}/swiftshader/libEGL.so" "${STAGEDIR}/${INSTALLDIR}/swiftshader/"
    install -m 644 "${BUILDDIR}/swiftshader/libGLESv2.so" "${STAGEDIR}/${INSTALLDIR}/swiftshader/"
  fi

  # libc++
  if [ -f "${BUILDDIR}/lib/libc++.so" ]; then
    install -m 755 -d "${STAGEDIR}/${INSTALLDIR}/lib/"

    install -m 644 -s "${BUILDDIR}/lib/libc++.so" "${STAGEDIR}/${INSTALLDIR}/lib/"
  fi

  # nacl_helper and nacl_helper_bootstrap
  # Don't use "-s" (strip) because this runs binutils "strip", which
  # mangles the special ELF program headers of nacl_helper_bootstrap.
  # Explicitly use eu-strip instead, because it doesn't have that problem.
  for file in nacl_helper nacl_helper_bootstrap; do
    buildfile="${BUILDDIR}/${file}"
    if [ -f "${buildfile}" ]; then
      strippedfile="${buildfile}.stripped"
      debugfile="${buildfile}.debug"
      "${BUILDDIR}/app_shell_installer/common/eu-strip" -o "${strippedfile}" -f "${debugfile}" "${buildfile}"
      install -m 755 "${strippedfile}" "${STAGEDIR}/${INSTALLDIR}/${file}"
    fi
  done
  # Don't use "-s" (strip) because this would use the Linux toolchain to
  # strip the NaCl binary, which has the potential to break it.  It
  # certainly resets the OSABI and ABIVERSION fields to non-NaCl values,
  # although the NaCl IRT loader doesn't care about these fields.  In any
  # case, the IRT binaries are already stripped by NaCl's build process.
  for filename in ${BUILDDIR}/nacl_irt_*.nexe; do
    # Re-check the filename in case globbing matched nothing.
    if [ -f "$filename" ]; then
      install -m 644 "$filename" "${STAGEDIR}/${INSTALLDIR}/`basename "$filename"`"
    fi
  done

  # launcher script and symlink
  process_template "${BUILDDIR}/app_shell_installer/common/wrapper" \
    "${STAGEDIR}/${INSTALLDIR}/${PACKAGE}"
  chmod 755 "${STAGEDIR}/${INSTALLDIR}/${PACKAGE}"
  if [ ! -f "${STAGEDIR}/${INSTALLDIR}/app-shell" ]; then
    ln -sn "${INSTALLDIR}/${PACKAGE}" \
      "${STAGEDIR}/${INSTALLDIR}/app-shell"
  fi
  ln -snf "${INSTALLDIR}/${PACKAGE}" \
    "${STAGEDIR}/usr/bin/${USR_BIN_SYMLINK_NAME}"
}
