#!/bin/sh
# Install the vpcatlas binary (command line and dashboard in one file).
#
#   curl -fsSL https://vpcatlas.com/install.sh | sh
#
# Environment:
#   VPCATLAS_VERSION      version to install, for example 0.1.0 (default: the latest release)
#   VPCATLAS_INSTALL_DIR  directory for the binary (default: /usr/local/bin when writable, else ~/.local/bin)
#
# The archive and SHA256SUMS are downloaded from the GitHub Release of https://github.com/vpcatlas/vpcatlas and the
# archive is checked against the checksum before anything is installed.

set -eu

REPO="vpcatlas/vpcatlas"

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

need() { command -v "$1" >/dev/null 2>&1 || fail "$1 is required and was not found"; }

need uname
need tar
need mktemp

if command -v curl >/dev/null 2>&1; then
  fetch() { curl -fsSL --retry 3 -o "$2" "$1"; }
  fetch_text() { curl -fsSL --retry 3 "$1"; }
elif command -v wget >/dev/null 2>&1; then
  fetch() { wget -q -O "$2" "$1"; }
  fetch_text() { wget -q -O - "$1"; }
else
  fail "curl or wget is required"
fi

case "$(uname -s)" in
  Linux) os=linux ;;
  Darwin) os=darwin ;;
  *) fail "unsupported operating system: $(uname -s). Binaries exist for Linux and macOS; on other systems use 'pipx install vpcatlas' or the Docker image vpcatlas/vpcatlas" ;;
esac

case "$(uname -m)" in
  x86_64 | amd64) arch=x86_64 ;;
  arm64 | aarch64) arch=arm64 ;;
  *) fail "unsupported architecture: $(uname -m). Binaries exist for x86_64 and arm64" ;;
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 verify the download"
fi

version="${VPCATLAS_VERSION:-}"
if [ -z "$version" ]; then
  say "Looking for the latest release..."
  version="$(fetch_text "https://api.github.com/repos/${REPO}/releases?per_page=1" |
    sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"v\{0,1\}\([^"]*\)".*/\1/p' | head -n 1)" || true
  [ -n "$version" ] || fail "could not read the latest release of ${REPO}; set VPCATLAS_VERSION, for example VPCATLAS_VERSION=0.1.0"
fi
version="${version#v}"

name="vpcatlas-${version}-${os}-${arch}"
base="https://github.com/${REPO}/releases/download/v${version}"

work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT HUP INT TERM

say "Downloading ${name}.tar.gz"
fetch "${base}/${name}.tar.gz" "${work}/${name}.tar.gz" || fail "download failed: ${base}/${name}.tar.gz (is ${version} a released version for ${os} ${arch}?)"
fetch "${base}/SHA256SUMS" "${work}/SHA256SUMS" || fail "download failed: ${base}/SHA256SUMS"

expected="$(awk -v f="${name}.tar.gz" '$2 == f || $2 == "*" f { print $1; exit }' "${work}/SHA256SUMS")"
[ -n "$expected" ] || fail "SHA256SUMS has no line for ${name}.tar.gz"
actual="$(sha256 "${work}/${name}.tar.gz")"
if [ "$expected" != "$actual" ]; then
  fail "checksum mismatch for ${name}.tar.gz: expected ${expected}, got ${actual}. Nothing was installed"
fi
say "Checksum verified"

tar -xzf "${work}/${name}.tar.gz" -C "$work" vpcatlas || fail "the archive does not contain a vpcatlas binary"

if [ -n "${VPCATLAS_INSTALL_DIR:-}" ]; then
  dir="$VPCATLAS_INSTALL_DIR"
elif [ -w /usr/local/bin ]; then
  dir=/usr/local/bin
else
  dir="${HOME:?HOME is not set}/.local/bin"
fi
mkdir -p "$dir" || fail "cannot create ${dir}"
[ -w "$dir" ] || fail "${dir} is not writable; set VPCATLAS_INSTALL_DIR to a directory you own"

# Move into place in two steps, so a running vpcatlas is never replaced half-written.
cp "${work}/vpcatlas" "${dir}/.vpcatlas.new"
chmod 755 "${dir}/.vpcatlas.new"
mv -f "${dir}/.vpcatlas.new" "${dir}/vpcatlas"
say "Installed ${dir}/vpcatlas"

case ":${PATH}:" in
  *":${dir}:"*) ;;
  *) say "Note: ${dir} is not on your PATH. Add it, for example: export PATH=\"${dir}:\$PATH\"" ;;
esac

"${dir}/vpcatlas" --version
