#!/bin/bash -e
#
# Build/cross-build packages and test Machinekit-HAL in Docker
#
# This script can be run manually or in Travis CI

###########################################################
# Configuration from environment, CL args and defaults
CMD=${CMD:-shell}
IMAGE=${IMAGE:-dovetailautomata/mk-cross-builder}
TAG=${TAG:-amd64_10}
JOBS=${JOBS:-$(nproc)}
BUILD_SOURCE=${BUILD_SOURCE:-true}  # update Changelog & source pkg

# CL arguments
while getopts c:i:t:j:nh? opt; do
    case "$opt" in
	c) CMD=$OPTARG ;;
	i) IMAGE=$OPTARG ;;
	t) TAG=$OPTARG ;;
	j) JOBS=$OPTARG ;;
	n) BUILD_SOURCE=false ;;
	?|h|*) echo "Usage:  $0 [ -i DOCKER-IMAGE ] [ -t DOCKER-TAG ]" \
	    "[ -c ( deb [ -n ] | test | [ shell ] [ COMMAND ARG ... ] ) ]" >&2
	    exit 1 ;;
    esac
done
shift $(($OPTIND - 1))

###########################################################
# Set build parameters

# Arch-specific:
case ${TAG} in
    amd64_*)
	BUILD_OPTS='-b'                  # Build all binary packages
	RUN_TESTS='runtests'             # Run tests on build arch
	;;
    i386_*)                              # Machine arch: i386
	BUILD_OPTS="-a i386"             # - Set machine arch
	;;& # Fall through
    armhf_*)                             # Machine arch: armhf
	BUILD_OPTS="-a armhf"            # - Set machine arch
	;;& # Fall through
    i386_*|armhf_*)                      # Cross-compile/foreign arch
	BUILD_OPTS+=" -B"                # - Only build arch binary packages
	BUILD_OPTS+=" -d"                # - Root fs missing build deps; force
	RUN_TESTS='true'                 # - Don't run tests
	BUILD_SOURCE=false               # - Don't build source package
	;;
    *) echo "Warning:  unknown tag '${TAG}'" >&2 ;;
esac

# Distro-specific:
case ${TAG} in
    *_8)
	PKG_CONFIGURE_ARGS="-prx"   # Enable Xenomai
	;;
    *)
	PKG_CONFIGURE_ARGS="-pr"    # Build posix and preempt-rt threads
	;;
esac

# Distro specific warnings level
case ${TAG} in
    *_8|*_9)
	WERROR_FLAG="-Werror"
	;;
    *)
	WERROR_FLAG=""  # Buster and above have many as yet unresolved warnings
	;;
esac

# DH_VERBOSE turn on verbose package debuilds
! ${MK_PACKAGE_VERBOSE:-false} || export DH_VERBOSE=1

# Parallel jobs in `make`
export DEB_BUILD_OPTIONS="parallel=${JOBS}"

# UID/GID to carry into Docker
UID_GID=${UID_GID:-`id -u`:`id -g`}

# Bind source directory:  parent of $PWD for packages
BIND_SOURCE_DIR="$(readlink -f $PWD/..)"

# Directory containing this script
SCRIPT_DIR="$(dirname $0)"

# Make TAG accessible to called programs
export TAG

###########################################################
# Generate command line

declare -a BUILD_CL DOCKER_EXTRA_OPTS
case $CMD in
    "shell"|"") # Interactive shell (default)
	DOCKER_EXTRA_OPTS=( --privileged --interactive )
	if test -z "$*"; then
	    BUILD_CL=( bash -i )
	else
	    BUILD_CL=( "$@" )
	fi
	;;
    "deb") # Build Debian packages
	DOCKER_EXTRA_OPTS=(
	    # Used in dpkg-buildpackage
	    -e DEB_BUILD_OPTIONS=$DEB_BUILD_OPTIONS
	    -e DH_VERBOSE=$DH_VERBOSE
	    # Used in scripts/build_source_package
	    -e DEBIAN_SUITE=$DEBIAN_SUITE
	    -e MAJOR_MINOR_VERSION=$MAJOR_MINOR_VERSION
	    -e PKGSOURCE=$PKGSOURCE
	    -e REPO_URL=$REPO_URL
	    -e TRAVIS_BRANCH=$TRAVIS_BRANCH
	    -e TRAVIS_PULL_REQUEST=$TRAVIS_PULL_REQUEST
	    -e TRAVIS_REPO=$TRAVIS_REPO
	    -e TRAVIS_REPO_SLUG=$TRAVIS_REPO_SLUG
            -e DPKG_CFLAGS="${DPKG_CFLAGS} ${WERROR_FLAG}"
	)

	BUILD_CL=( bash -xec "
            # configure source package
            debian/configure ${PKG_CONFIGURE_ARGS};

            # update Changelog and build source package
            $SCRIPT_DIR/build_source_package $BUILD_SOURCE

            # build binary packages
            dpkg-buildpackage -uc -us ${BUILD_OPTS} -j$JOBS
            "
	)
	;;
    "test") # RIP build and regression tests
	if test "$TEST_DEBUG" = true; then
	    DOCKER_EXTRA_OPTS=( -e MSGD_OPTS=-s -e DEBUG=5 )
	fi
	TEST_ARGS="${TEST_ARGS:-tests}"
	BUILD_CL=( bash -xec "
            # Set up build:  \`autoconf\` and \`make\`
	    (
		cd src;
		./autogen.sh;
		./configure --host=\$HOST_MULTIARCH --with-posix;
	    )

            # Build
	    make -C src -j${JOBS};

            # Set up runtime:  setuid, environment, ini
	    sudo make -C src setuid || true;  # Don't exit if this fails
	    . scripts/rip-environment;
	    echo -e 'ANNOUNCE_IPV4=0\nANNOUNCE_IPV6=0' >> \
		etc/linuxcnc/machinekit.ini;
	    tail -2 etc/linuxcnc/machinekit.ini;
	    flavor;

            # Run regression tests
	    ${RUN_TESTS} ${TEST_ARGS}"
	)
	;;
    "docs") # Just build docs
	BUILD_CL=( bash -xec "
	    cd src ;
	    ./autogen.sh ;
	    ./configure --enable-build-documentation ;
	    make docpages i_docpages ;"
	)
	;;
    *)   echo "Unknown command '$CMD'" >&2; exit 1 ;;
esac

###########################################################
# Update new container image and add custom /etc/passwd

if test -z "$NO_PULL"; then
    docker pull ${IMAGE}:${TAG}
fi

if test ${UID_GID/:*/} != 1000; then
    echo "Updating /etc/passwd for UID $TRAVIS_UID" >&2
    NEWTAG=${TAG}_custom
    docker build -t ${IMAGE}:${NEWTAG} - <<EOF
FROM ${IMAGE}:${TAG}
RUN sed -i "s/\${USER}:x:\${UID}:/\${USER}:x:${UID_GID/:*/}:/" /etc/passwd
RUN echo '${USER}:*:17967:0:99999:7:::' >> /etc/shadow
ENV UID=${UID_GID/:*/}
EOF
else
    NEWTAG=${TAG}
fi

###########################################################
# Run build

set -x  # Show user the command

# Run the Docker container as follows:
# - Remove container after exit
# - Run interactively with terminal
# - Add any `DOCKER_EXTRA_OPTS` from above
# - As Travis CI user/group
# - Bind-mount home and source directories; start in source directory
# - Pass environment variable `TAG`
# - Set hostname to $IMAGE:$TAG (replace `/` and `:` with `-`)
# - Run build command as set above
# hide --it
exec docker run \
    --rm \
    --tty \
    "${DOCKER_EXTRA_OPTS[@]}" \
    -u ${UID_GID} -e USER=${USER} \
    -v ${HOME}:${HOME} -e HOME=${HOME} \
    -v ${BIND_SOURCE_DIR}:${BIND_SOURCE_DIR} -w ${PWD} \
    -e TAG=${TAG} \
    -h ${IMAGE//[\/:]/-}-${TAG} \
    ${IMAGE}:${NEWTAG} \
    "${BUILD_CL[@]}"
