#!/bin/bash
#
# This script can be used to facilitate supervisor development. Its core feature is allowing
# faster development iterations by bind-mounting the local './dist' directly into the running
# supervisor container.
#
# Setting the '--mount-nm' flag in either 'run' or 'buildrun' action will bind-mount
# './node_modules/' into the running supervisor. In this case, it's up to the developer
# to make sure that the correct dependencies are installed.
#
# Usage: dindctl action [options]
#
# Actions:
# 	build					build local supervisor image - you can override image name with --image.
# 	run [options]			build dind host container, run it (with name resin_supervisor_1), which will include the specified supervisor image and run it.
# 	buildrun [options]		run 'build' and then immediately 'run' the built container.
# 	refresh					recompile sources in './src' and restart supervisor container on dind host - requires --mount-dist in order to work properly.
# 	logs [-f]				print out supervisor log files - use '-f' to follow instead, or any other arguments you'd send to journalctl.
# 	stop					stop dind supervisor host container.
# Options:
# 	--arch | -a  [arch]		architecture of the supervisor to build (default: amd64 )
# 	--image | -i [image]	image name for supervisor image to build/use ( default: resin/$ARCH-supervisor:master )
# 	--dind-image [image]	image name for the dind host container
# 	--dind-container [name]	container name for the dind host container ( default: resin_supervisor_1 )
# 	--mount-dist			bind-mount './dist/' (where webpack stores the built js) from local development environment into supervisor container.
# 	--mount-nm				bind-mount './node_modules/' from local development environment into supervisor container.
# 	--preload | -p			use tools/dev/apps.json to preload an application image into the dind host.
# 	--ssh					enable a passwordless dropbear ssh server on the dind host
# 	--config | -c [file]	path to config.json, relative to tools/dind ( default: config.json )
#
# See README.md for examples.
#
# The script requires make and docker.
#

THIS_FILE=$0

set -o errexit
set -o pipefail

DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
SUPERVISOR_BASE_DIR="${DIR}"

ARCH="amd64"
SUPERVISOR_IMAGE="resin/${ARCH}-supervisor:master"
PASSWORDLESS_DROPBEAR="false"
SUPERVISOR_EXTRA_MOUNTS=""
DIST_MOUNTED="false"
DIND_IMAGE="resin-supervisor-dind"
CONTAINER_NAME="resin_supervisor_1"
PRELOADED_IMAGE=""
OPTIMIZE="true"
CONFIG_FILENAME="config.json"

function showHelp {
	cat $THIS_FILE | awk '{if(/^#/)print;else exit}' | tail -n +2 | sed 's/\#//' | sed 's|dindctl|'$THIS_FILE'|'
}

function parseOptions {
	while [[ $# -ge 1 ]]
	do
		case $1 in
			--mount-dist)
				DIST_MOUNTED="true"
				SUPERVISOR_EXTRA_MOUNTS="$SUPERVISOR_EXTRA_MOUNTS -v /resin-supervisor/dist:/usr/src/app/dist"
				;;
			--mount-nm)
				SUPERVISOR_EXTRA_MOUNTS="$SUPERVISOR_EXTRA_MOUNTS -v /resin-supervisor/node_modules:/usr/src/app/node_modules"
				;;
			-p|--preload)
				PRELOADED_IMAGE="true"
				;;
			--ssh)
				PASSWORDLESS_DROPBEAR="true"
				;;
			-i|--image)
				SUPERVISOR_IMAGE="$2"
				shift || { echo "--image provided not specified" && exit 1; }
				;;
			-c|--config)
				CONFIG_FILENAME="$2"
				shift || { echo "--config provided not specified" && exit 1; }
				;;
			--dind-image)
				DIND_IMAGE="$2"
				shift || { echo "--dind-image provided not specified" && exit 1; }
				;;
			--dind-container)
				CONTAINER_NAME="$2"
				shift || { echo "--dind-container provided not specified" && exit 1; }
				;;
			-a|--arch)
				ARCH="$2"
				shift || { echo "--arch provided not specified" && exit 1; }
				;;
			--no-optimize)
				OPTIMIZE="false"
				;;
			*)
				echo "Warning: unknown argument: $arg"
				;;
		esac
		shift
	done
}

function buildSupervisor {
	echo "Building and deploying for architecture $ARCH and tagging as $IMAGE"
	make -C "$SUPERVISOR_BASE_DIR" \
		ARCH="$ARCH" \
		IMAGE="$SUPERVISOR_IMAGE" \
		supervisor
}

function buildSupervisorSrc {
	if [ "$OPTIMIZE" = "true" ]; then
		echo "Rebuilding supervisor source"
		( cd "$SUPERVISOR_BASE_DIR" && npm install && npm run build )
	else
		echo "Rebuilding supervisor source without optimizations"
		( cd "$SUPERVISOR_BASE_DIR" && npm install && npm run build-no-optimize )
	fi
}

function refreshSupervisorSrc {
	buildSupervisorSrc
	echo "Restarting the supervisor container"
	docker exec -ti $CONTAINER_NAME docker restart resin_supervisor
}

function runDind {
	if [ "$DIST_MOUNTED" = "true" ]; then
		buildSupervisorSrc
		echo "Running with mounted dist folder"
	fi
	if [ "$PRELOADED_IMAGE" = "true" ]; then
		echo "Running with preloaded apps"
	fi
	if ! ( docker inspect $SUPERVISOR_IMAGE &> /dev/null ); then
		echo "$SUPERVISOR_IMAGE not available locally, pulling"
		docker pull $SUPERVISOR_IMAGE
	fi
	echo "Starting dind supervisor"
	make -C "$SUPERVISOR_BASE_DIR" \
		ARCH="$ARCH" \
		SUPERVISOR_IMAGE="$SUPERVISOR_IMAGE" \
		PASSWORDLESS_DROPBEAR="$PASSWORDLESS_DROPBEAR" \
		SUPERVISOR_EXTRA_MOUNTS="$SUPERVISOR_EXTRA_MOUNTS" \
		PRELOADED_IMAGE="$PRELOADED_IMAGE" \
		IMAGE="$DIND_IMAGE" \
		CONTAINER_NAME="$CONTAINER_NAME" \
		CONFIG_FILENAME="$CONFIG_FILENAME" \
		run-supervisor
}

function stopDind {
	echo "Stopping dind supervisor"
	make -C "$SUPERVISOR_BASE_DIR" CONTAINER_NAME="$CONTAINER_NAME" stop-supervisor
}

function logs {
	docker exec -ti $CONTAINER_NAME journalctl $@
}

action="$1"
shift || true

if [ "$action" = "logs" ]; then
	logs "$@"
else
	parseOptions "$@"
	case $action in
		build)
			buildSupervisor
			;;
		run)
			runDind
			;;
		buildrun)
			buildSupervisor && runDind
			;;
		refresh)
			refreshSupervisorSrc
			;;
		stop)
			stopDind
			;;
		*)
			showHelp
			;;
	esac
fi