#!/bin/sh
# Installs the Dormeto CLI (https://github.com/Dormeto/cli): the archive of the release for this machine, its SHA-256
# checked against checksums.txt, then `dormeto` copied into a directory of yours. No sudo, nothing else is changed.
#
#   curl -fsSL https://dormeto.com/install.sh | sh
#
# Variables: DORMETO_VERSION (without the v; default: the latest release), DORMETO_INSTALL_DIR (default:
# $HOME/.local/bin), DORMETO_DOWNLOAD_URL (default: https://github.com/Dormeto/cli/releases/download/v<version>) and
# DORMETO_RELEASES_URL (default: https://github.com/Dormeto/cli/releases), both for tests.
set -eu

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

repo=https://github.com/Dormeto/cli
releases="${DORMETO_RELEASES_URL:-$repo/releases}"

# curl or wget
if command -v curl >/dev/null 2>&1; then
  fetch() { curl -fsSL --connect-timeout 15 --max-time 300 --retry 2 -o "$2" "$1"; }
  # The Location a URL redirects to (not followed: the tag's page is not needed).
  redirect_of() { curl -fsS --connect-timeout 15 --max-time 30 -o /dev/null -w '%{redirect_url}' "$1"; }
elif command -v wget >/dev/null 2>&1; then
  fetch() { wget -q -T 30 -t 3 -O "$2" "$1"; }
  # BusyBox wget has no --max-redirect: -S --spider prints the headers, the first Location is the target.
  redirect_of() { wget -S -T 30 -t 3 --spider -O /dev/null "$1" 2>&1 | sed -n 's/^ *[Ll]ocation: *//p' | tr -d '\r' | head -n 1 || true; }
else
  fail "curl or wget is required"
fi

case "$(uname -s)" in
  Darwin) os=darwin ;;
  Linux) os=linux ;;
  MINGW* | MSYS* | CYGWIN*)
    fail "Windows is not supported by this script. Download dormeto_<version>_windows_amd64.zip (_arm64 on an ARM PC)
from the latest release, unzip it and put dormeto.exe in a folder of your PATH: $releases/latest" ;;
  *) fail "unsupported system: $(uname -s) (macOS and Linux only)" ;;
esac

case "$(uname -m)" in
  x86_64 | amd64) arch=amd64 ;;
  aarch64 | arm64) arch=arm64 ;;
  *) fail "unsupported architecture: $(uname -m) (amd64 and arm64 only)" ;;
esac

if command -v sha256sum >/dev/null 2>&1; then
  sha256() { sha256sum "$1" | cut -d ' ' -f 1; }
elif command -v shasum >/dev/null 2>&1; then
  sha256() { shasum -a 256 "$1" | cut -d ' ' -f 1; }
else
  fail "sha256sum or shasum is required to check the download"
fi

version="${DORMETO_VERSION:-}"
version="${version#v}"
if [ -z "$version" ]; then
  # The redirect of /releases/latest names the tag, without the GitHub API's rate limit.
  tag="$(redirect_of "$releases/latest" 2>/dev/null | sed -n 's#.*/tag/##p' | tail -n 1)" || tag=""
  version="${tag#v}"
  [ -n "$version" ] || fail "cannot find the latest release of $repo; set DORMETO_VERSION (for example DORMETO_VERSION=1.0.0)"
fi

base="${DORMETO_DOWNLOAD_URL:-$repo/releases/download/v$version}"
archive="dormeto_${version}_${os}_${arch}.tar.gz"
dir="${DORMETO_INSTALL_DIR:-${HOME:?HOME is not set}/.local/bin}"

tmp="$(mktemp -d)"
# The EXIT trap cleans; a signal exits (129, 130, 143), which runs it.
trap 'rm -rf "$tmp"' EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM

say "Downloading Dormeto $version for $os/$arch"
fetch "$base/$archive" "$tmp/$archive" || fail "cannot download $base/$archive"
fetch "$base/checksums.txt" "$tmp/checksums.txt" || fail "cannot download $base/checksums.txt"

want="$(awk -v f="$archive" '$2 == f || $2 == "*" f { print $1; exit }' "$tmp/checksums.txt")"
[ -n "$want" ] || fail "$archive is not in checksums.txt"
got="$(sha256 "$tmp/$archive")"
[ "$got" = "$want" ] || fail "checksum mismatch for $archive (expected $want, got $got); nothing installed"

mkdir "$tmp/unpacked"
tar -xzf "$tmp/$archive" -C "$tmp/unpacked" dormeto || fail "cannot unpack $archive"
# Absolute, for the messages and the PATH hint (a relative one means nothing in another directory); symlinks are kept
# as given, so a directory on PATH under its own name is recognised.
case $dir in /*) ;; *) dir="${PWD%/}/$dir" ;; esac
mkdir -p "$dir" || fail "cannot create $dir; set DORMETO_INSTALL_DIR to a directory you can write"
cp "$tmp/unpacked/dormeto" "$dir/dormeto.new" && chmod 755 "$dir/dormeto.new" && mv -f "$dir/dormeto.new" "$dir/dormeto" \
  || { rm -f "$dir/dormeto.new"; fail "cannot write $dir/dormeto; set DORMETO_INSTALL_DIR to a directory you can write"; }

say "Installed $dir/dormeto"
case ":$PATH:" in
  *":$dir:"*) ;;
  *) say "Add $dir to your PATH, for example: export PATH=\"$dir:\$PATH\"" ;;
esac
say "Next: dormeto aws estimate --profile <profile> --uptime"
