#!/bin/sh
set -e
# InAccel for Linux installation script.
#
# This script is intended as a convenient way to configure inaccel's package
# repositories and to install InAccel, This script is not recommended for
# production environments. Before running this script, make yourself familiar
# with potential risks and limitations, and refer to the installation manual
# at https://docs.inaccel.com/install/ for alternative installation methods.
#
# The script:
#
# - Requires `root` or `sudo` privileges to run.
# - Attempts to detect your Linux distribution and version and configure your
#   package management system for you.
# - Doesn't allow you to customize most installation parameters.
# - Installs dependencies and recommendations without asking for confirmation.
# - Installs the latest stable release of InAccel, InAccel CLI, InAccel Docker,
#   and InAccel FPGA. When using this script to provision a machine, this may
#   result in unexpected major version upgrades of these packages. Always test
#   upgrades in a test environment before deploying to your production systems.
# - Isn't designed to upgrade an existing InAccel installation. When using the
#   script to update an existing installation, dependencies may not be updated
#   to the expected version, resulting in outdated versions.
#
# Usage
# ==============================================================================
#
# To install the latest stable versions of InAccel, InAccel CLI, InAccel Docker,
# InAccel FPGA, and their dependencies:
#
# 1. download the script
#
#   $ curl -fsSL https://setup.inaccel.com/repository -o setup-inaccel.sh
#
# 2. verify the script's content
#
#   $ cat setup-inaccel.sh
#
# 3. run the script either as root, or using sudo to perform the installation.
#
#   $ sudo sh setup-inaccel.sh install
#
# ==============================================================================


DEFAULT_DOWNLOAD_URL="https://dl.cloudsmith.io/public/inaccel/stable"
if [ -z "$DOWNLOAD_URL" ]; then
	DOWNLOAD_URL=$DEFAULT_DOWNLOAD_URL
fi

DEFAULT_SETUP_URL="https://setup.inaccel.com"
if [ -z "$SETUP_URL" ]; then
	SETUP_URL="$DEFAULT_SETUP_URL"
fi

install=${install:-}
while [ $# -gt 0 ]; do
	case "$1" in
		install)
			install=1
			;;
		*)
			echo "Illegal option $1"
			;;
	esac
	shift $(( $# > 0 ? 1 : 0 ))
done

command_exists() {
	command -v "$@" > /dev/null 2>&1
}

is_install() {
	if [ -z "$install" ]; then
		return 1
	else
		return 0
	fi
}

get_distribution() {
	lsb_dist=""
	# Every system that we officially support has /etc/os-release
	if [ -r /etc/os-release ]; then
		lsb_dist="$(. /etc/os-release && echo "$ID")"
	fi
	# Returning an empty string here should be alright since the
	# case statements don't act unless you provide an actual value
	echo "$lsb_dist"
}

# Check if this is a forked Linux distro
check_forked() {

	# Check for lsb_release command existence, it usually exists in forked distros
	if command_exists lsb_release; then
		# Check if the `-u` option is supported
		set +e
		lsb_release -a -u > /dev/null 2>&1
		lsb_release_exit_code=$?
		set -e

		# Check if the command has exited successfully, it means we're in a forked distro
		if [ "$lsb_release_exit_code" = "0" ]; then
			# Print info about current distro
			cat <<-EOF
			You're using '$lsb_dist' version '$dist_version'.
			EOF

			# Get the upstream release info
			lsb_dist=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'id' | cut -d ':' -f 2 | tr -d '[:space:]')
			dist_version=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'codename' | cut -d ':' -f 2 | tr -d '[:space:]')

			# Print info about upstream distro
			cat <<-EOF
			Upstream release is '$lsb_dist' version '$dist_version'.
			EOF
		else
			if [ -r /etc/debian_version ] && [ "$lsb_dist" != "ubuntu" ]; then
				# We're Debian and don't even know it!
				lsb_dist=debian
				dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')"
				case "$dist_version" in
					12)
						dist_version="bookworm"
					;;
					11)
						dist_version="bullseye"
					;;
					10)
						dist_version="buster"
					;;
					9)
						dist_version="stretch"
					;;
					8)
						dist_version="jessie"
					;;
				esac
			fi
		fi
	fi
}

do_setup() {
	echo "# Executing InAccel repository setup script"

	user="$(id -un 2>/dev/null || true)"

	sh_c='sh -c'
	if [ "$user" != 'root' ]; then
		if command_exists sudo; then
			sh_c='sudo -E sh -c'
		elif command_exists su; then
			sh_c='su -c'
		else
			cat >&2 <<-'EOF'
			Error: this installer needs the ability to run commands as root.
			We are unable to find either "sudo" or "su" available to make this happen.
			EOF
			exit 1
		fi
	fi

	# perform some very rudimentary platform detection
	lsb_dist=$( get_distribution )
	lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"

	case "$lsb_dist" in

		debian)
			dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')"
			case "$dist_version" in
				12)
					dist_version="bookworm"
				;;
				11)
					dist_version="bullseye"
				;;
				10)
					dist_version="buster"
				;;
				9)
					dist_version="stretch"
				;;
				8)
					dist_version="jessie"
				;;
			esac
		;;

		ubuntu)
			if command_exists lsb_release; then
				dist_version="$(lsb_release --codename | cut -f2)"
			fi
			if [ -z "$dist_version" ] && [ -r /etc/lsb-release ]; then
				dist_version="$(. /etc/lsb-release && echo "$DISTRIB_CODENAME")"
			fi
		;;

	esac

	# Check if this is a forked Linux distro
	check_forked

	# Run setup for each distro accordingly
	case "$lsb_dist" in
		debian|ubuntu)
			pre_reqs="apt-transport-https ca-certificates curl"
			apt_repo="deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/inaccel.asc] $DOWNLOAD_URL/deb/$lsb_dist $dist_version main"
			(
				set -x
				$sh_c 'apt-get update -qq >/dev/null'
				$sh_c "DEBIAN_FRONTEND=noninteractive apt-get install -y -qq $pre_reqs >/dev/null"
				$sh_c 'install -m 0755 -d /etc/apt/keyrings'
				$sh_c "curl -fsSL \"$SETUP_URL/gpg\" -o /etc/apt/keyrings/inaccel.asc"
				$sh_c "chmod a+r /etc/apt/keyrings/inaccel.asc"
				$sh_c "echo \"$apt_repo\" > /etc/apt/sources.list.d/inaccel.list"
				$sh_c 'apt-get update -qq >/dev/null'
			)
			(
				if is_install; then
					set -x
					$sh_c 'DEBIAN_FRONTEND=noninteractive apt-get install -y -qq inaccel inaccel-cli inaccel-docker inaccel-fpga >/dev/null'
				fi
			)
			exit 0
			;;
		amzn|centos|fedora|rhel)
			if command_exists dnf; then
				pkg_manager="dnf"
				pkg_manager_flags="--best"
				config_manager="dnf config-manager"
				pre_reqs="dnf-plugins-core"
			else
				pkg_manager="yum"
				pkg_manager_flags=""
				config_manager="yum-config-manager"
				pre_reqs="yum-utils"
			fi
			repo_file_url="$SETUP_URL/inaccel.repo"
			(
				set -x
				$sh_c "$pkg_manager $pkg_manager_flags install -y -q $pre_reqs"
				$sh_c "$config_manager --add-repo $repo_file_url"

				$sh_c "$pkg_manager makecache"
			)
			(
				if is_install; then
					set -x
					$sh_c "$pkg_manager $pkg_manager_flags install -y -q inaccel inaccel-cli inaccel-docker inaccel-fpga"
				fi
			)
			exit 0
			;;
		*)
			echo
			echo "ERROR: Unsupported distribution '$lsb_dist'"
			echo
			exit 1
			;;
	esac
	exit 1
}

# wrapped up in a function so that we have some protection against only getting
# half the file during "curl | sh"
do_setup
