#!/bin/sh
# Installs Neurotrader on Debian and Ubuntu, and on Fedora and the EL10 family (RHEL, Rocky Linux,
# AlmaLinux).
#
#     curl -fsSL https://download.neurotrader.ametis.io/latest/neurotrader-linux-x64.sh | sh
#     wget -qO- https://download.neurotrader.ametis.io/latest/neurotrader-linux-x64.sh | sh
#
# One script per release, pinned to it: this one installs the version named below, from the
# release directory beside it on the downloads host. It downloads the release's three packages in
# the machine's format (the neurotrader metapackage, and the neurotrader-daemon and neurotrader-gui
# packages it pins), checks them against the release's SHA256SUMS, and installs them with the
# distribution's package manager, which resolves their dependencies: apt with the .deb files where
# there is apt-get, dnf with the .rpm files where there is dnf. Running a newer release's script
# over an installed Neurotrader upgrades it; both keep /etc/neurotrader/config.yaml and
# /var/lib/neurotrader, and the engine's service is restarted under the new binary.
#
# On EL10 the desktop application's WebKitGTK comes from EPEL, which the distribution does not
# enable: on Rocky Linux, AlmaLinux and CentOS Stream the script installs epel-release from the
# distribution's own repositories and says so; on RHEL, whose EPEL needs a subscription repository
# enabled first, it stops and says what to run. Fedora carries WebKitGTK itself.
#
# The downloads happen as the user who runs the script; only the install step needs root, and it
# goes through sudo when the script is not run as root. POSIX sh throughout, so that it runs under
# dash, the /bin/sh of Debian and Ubuntu, exactly as under bash.
#
# NEUROTRADER_DOWNLOADS_URL names another host to download from, for a mirror or a test.
set -eu

VERSION="0.1.0-alpha.4"
HOST="${NEUROTRADER_DOWNLOADS_URL:-https://download.neurotrader.ametis.io}"
RELEASE="$HOST/releases/$VERSION"

say() { printf '%s\n' "$*"; }
fail() { printf 'neurotrader: %s\n' "$*" >&2; exit 1; }

if command -v apt-get >/dev/null 2>&1; then
  FORMAT=deb
  command -v dpkg >/dev/null 2>&1 || fail "dpkg was not found"
  arch=$(dpkg --print-architecture)
  [ "$arch" = "amd64" ] || fail "the packages are built for amd64, and this machine is $arch"
elif command -v dnf >/dev/null 2>&1; then
  FORMAT=rpm
  arch=$(uname -m)
  [ "$arch" = "x86_64" ] || fail "the packages are built for x86_64, and this machine is $arch"
else
  fail "this installer is for Debian and Ubuntu (apt-get) and for Fedora and EL10 (dnf), and neither was found. The packages are at $RELEASE/"
fi
PACKAGES="neurotrader-$VERSION-linux-x64.$FORMAT neurotrader-daemon-$VERSION-linux-x64.$FORMAT neurotrader-gui-$VERSION-linux-x64.$FORMAT"

if [ "$(id -u)" -eq 0 ]; then
  SUDO=""
elif command -v sudo >/dev/null 2>&1; then
  SUDO="sudo"
else
  fail "the install step needs root: run this as root, or install sudo"
fi

# EPEL on the EL10 family, before anything is downloaded, so a machine that cannot have it stops
# before it has fetched a release. /etc/os-release names the distribution; Fedora's ID_LIKE does not
# include rhel, so it never reaches this.
if [ "$FORMAT" = "rpm" ] && [ -r /etc/os-release ]; then
  os_id=$(. /etc/os-release && printf '%s' "${ID:-}")
  os_like=$(. /etc/os-release && printf '%s' "${ID_LIKE:-}")
  case " $os_id $os_like " in
    *" rhel "*)
      if ! rpm -q epel-release >/dev/null 2>&1; then
        case "$os_id" in
          rhel)
            fail "the desktop application needs EPEL, which RHEL does not enable. Run: sudo subscription-manager repos --enable codeready-builder-for-rhel-10-x86_64-rpms && sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm, then run this again"
            ;;
          *)
            say "Enabling EPEL, where the desktop application's WebKitGTK comes from"
            $SUDO dnf install -y -q epel-release
            ;;
        esac
      fi
      ;;
  esac
fi

if command -v curl >/dev/null 2>&1; then
  fetch() { curl -fsSL -o "$2" "$1"; }
elif command -v wget >/dev/null 2>&1; then
  fetch() { wget -q -O "$2" "$1"; }
else
  fail "neither curl nor wget was found"
fi

tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT INT TERM
# apt reads local packages as its own unprivileged user and warns about a directory it cannot enter.
chmod 755 "$tmp"

say "Downloading Neurotrader $VERSION from $RELEASE"
for file in $PACKAGES SHA256SUMS; do
  fetch "$RELEASE/$file" "$tmp/$file" || fail "could not download $RELEASE/$file"
done

# SHA256SUMS covers every file of the release; only the three downloaded here are checked. A line
# is "<hash>  <name>", or "<hash> *<name>" from a sha256sum in binary mode; both are accepted.
(
  cd "$tmp"
  for file in $PACKAGES; do
    grep -E "[ *]$file\$" SHA256SUMS || exit 1
  done > checked.sums
  sha256sum -c --quiet checked.sums
) || fail "a downloaded package does not match the published checksums"

install=""
for file in $PACKAGES; do
  install="$install $tmp/$file"
done
if [ "$FORMAT" = "deb" ]; then
  say "Installing with apt"
  $SUDO apt-get update -q || say "apt-get update failed; installing with the package lists as they are"
  # shellcheck disable=SC2086
  $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y -q $install
else
  say "Installing with dnf"
  # shellcheck disable=SC2086
  $SUDO dnf install -y -q $install
fi

say ""
if command -v systemctl >/dev/null 2>&1 && systemctl is-active --quiet neurotrader; then
  say "Neurotrader $VERSION is installed and the engine is running as a service."
  say "Start the app from the application menu, or run: neurotrader-gui"
else
  say "Neurotrader $VERSION is installed, but the engine's service is not running."
  say "See: journalctl -u neurotrader"
fi
