#!/bin/bash

if [[ -f ~/.config/scylladb/dbuild ]]; then
    . ~/.config/scylladb/dbuild
fi

if which docker >/dev/null 2>&1 ; then
  tool=${DBUILD_TOOL-docker}
elif which podman >/dev/null 2>&1 ; then
  tool=${DBUILD_TOOL-podman}
else
  die "Please make sure you install either podman or docker on this machine to run dbuild"
fi

here="$(realpath $(dirname "$0"))"
toplevel="$(realpath "$here/../..")"
group_args=()
docker_args=()
image="$(<"$here/image")"

for gid in $(id -G); do
    group_args+=(--group-add "$gid")
done

interactive=

function help () {
    cat <<EOF 1>&2
NAME
    $(basename $0) - Run a command in scylla's frozen toolchain docker build image.

SYNOPSIS
    $0 [OPTIONS --] [command [arg ...]]

DESCRIPTION
    $(basename $0) is used mainly to build scylla in a docker image containing
    a frozen version of the toolchain.

    When no command is provided, $(basename $0) runs an interactive shell in
    the docker instance.  The image to use is taken by default from "$(dirname $0)/image".
    It may be overriden using the --image option.

    When providing docker options, the options list must be terminated with \`--'.

OPTIONS
   -h | --help
       Print this help message.

   --image [IMAGE]
       Use the specified docker IMAGE.
       If omitted, list the available images using \`docker image ls'

   -i | --interactive
       Run an interactive session.

   See \`docker help run' for available options.

ENVIRONMENT

    SCYLLADB_DBUILD this variable, which can be a string or a bash
                    array, is prepended to the parmeters passed to
                    docker. This can be used to mount the ccache
                    directory (~/.ccache) and set up environment
                    variables (e.g. CCACHE_PREFIX)

    If the file ~/.config/scylladb/dbuild exists, it is sourced. This can
    be used to set up the SCYLLADB_DBUILD environment variable.
EOF
    exit 0
}

function die () {
    msg="$1"
    if [[ -n "$msg" ]]; then
        echo "$(basename $0): $msg." 1>&2
    fi
    cat <<EOF 1>&2

Run \`$0 --help' to print the full help message.
EOF
    exit 1
}

if [[ $# -eq 0 ]]; then
    interactive=y
    docker_args=(-it)
elif [[ "$1" = -* ]]; then
    while [[ "$1" != "--" && $# != 0 ]]; do
	case "$1" in
            -h|--help)
                help
                ;;
            --image)
                image="$2"
                shift 2
                if [[ -z "$image" ]]; then
                    die "Expected docker image identifier to follow the --image option"
                fi
                if ! $tool image inspect "$image" >/dev/null && ! $tool image pull "$image"; then
                    die
                fi
                continue
                ;;
	    --*)
		if [[ "$1" = --interactive || "$1" = --interactive=true ]]; then
		    interactive=y
		fi
		;;
	    -*)
		if [[ "$1" = -*i* ]]; then
		    interactive=y
		fi
		;;
	    *)
		;;
	esac
	docker_args+=("$1")
	shift
    done
    if [[ "$1" != "--" ]]; then
        die "Expected '--' to terminate docker flag list"
    fi
    shift
fi

if [[ $# != 0 ]]; then
    args=("$@")
else
    args=(/bin/bash -i)
fi

MAVEN_LOCAL_REPO="$HOME/.m2"

mkdir -p "$MAVEN_LOCAL_REPO"

is_podman="$($tool --help | grep -o podman)"

docker_common_args=()

docker_common_args+=("${SCYLLADB_DBUILD[@]}")

if [ -z "$is_podman" ]; then
    unset TMP_PASSWD
    docker_common_args+=(
       -u "$(id -u):$(id -g)"
       "${group_args[@]}"
       -v /etc/passwd:/etc/passwd:ro
       -v /etc/group:/etc/group:ro
       )
else
    TMP_PASSWD=$(mktemp --tmpdir passwd.XXXXXX)
    FULLNAME=$(getent passwd $USER | cut -d ':' -f 5)
    echo "$USER:x:0:0:$FULLNAME:$HOME:/bin/bash" > "$TMP_PASSWD"
    docker_common_args+=(-v "$TMP_PASSWD:/etc/passwd:ro")
fi

if [ "$PWD" != "$toplevel" ]; then
     docker_common_args+=(-v "$toplevel:$toplevel:z")
fi

# podman cannot relabel system directories like /tmp, but it can
# relable directories we own, so we map a temporary directory to /tmp

tmpdir=$(mktemp -d)

docker_common_args+=(
       --pids-limit -1 \
       --network host \
       --cap-add SYS_PTRACE \
       -v "$PWD:$PWD:z" \
       -v "$tmpdir:/tmp:z" \
       -v "$MAVEN_LOCAL_REPO:$MAVEN_LOCAL_REPO:z" \
       -v /etc/localtime:/etc/localtime:ro \
       -w "$PWD" \
       -e HOME \
       "${docker_args[@]}" \
       "$image" \
       "${args[@]}"
)

cleanup() {
    rm -rf "$tmpdir"
    if [ -v TMP_PASSWD ]; then
        rm -f "$TMP_PASSWD"
    fi
}

if [[ -n "$interactive" || -n "$is_podman" ]]; then
    # If --interactive was given on the command line, we can't run in detached mode
    # as it will be impossible to interact with the container.

    # We also avoid detached mode with podman, which doesn't need it
    # (it does not proxy SIGTERM) and doesn't work well with it.
    $tool run --rm "${docker_common_args[@]}"
    ret=$?
    cleanup
    exit $ret
fi

container=$(
    $tool run \
       "--detach=true" \
       "${docker_common_args[@]}"
)

kill_it() {
    if [[ -n "$container" ]]; then
        docker rm -f "$container" > /dev/null
        container=
    fi
    cleanup
}

trap kill_it SIGTERM SIGINT SIGHUP EXIT

$tool logs --follow "$container"

if [[ -n "$container" ]]; then
    exitcode="$($tool wait "$container")"
else
    exitcode=99
fi

kill_it

trap - SIGTERM SIGINT SIGHUP EXIT

# after "docker kill", docker wait will not print anything
[[ -z "$exitcode" ]] && exitcode=1

exit "$exitcode"
