#!/usr/bin/env bash
#
# This script builds a development TimescaleDB image from the
# currently checked out source on the host.
#
SCRIPT_DIR=$(dirname $0)
BASE_DIR=${PWD}/${SCRIPT_DIR}/..
PG_VERSION=${PG_VERSION:-14.3}
PG_IMAGE_TAG=${PG_IMAGE_TAG:-${PG_VERSION}-alpine}
BUILD_CONTAINER_NAME=${BUILD_CONTAINER_NAME:-pgbuild}
BUILD_IMAGE_NAME=${BUILD_IMAGE_NAME:-$USER/pgbuild}
IMAGE_NAME=${IMAGE_NAME:-$USER/timescaledb}
GIT_ID=$(git -C ${BASE_DIR} describe --dirty --always | sed -e "s|/|_|g")
TAG_NAME=${TAG_NAME:-$GIT_ID}
BUILD_TYPE=${BUILD_TYPE:-Debug}
USE_OPENSSL=${USE_OPENSSL:-true}
PUSH_PG_IMAGE=${PUSH_PG_IMAGE:-false}
GENERATE_DOWNGRADE_SCRIPT=${GENERATE_DOWNGRADE_SCRIPT:-OFF}

# Full image identifiers
PG_IMAGE=${BUILD_IMAGE_NAME}:${PG_IMAGE_TAG}
TS_IMAGE=${IMAGE_NAME}:${TAG_NAME}

trap remove_build_container EXIT

image_exists() {
    [[ $(docker image ls -f "reference=$1" -q) ]]
}

postgres_build_image_exists() {
    image_exists ${PG_IMAGE}
}

timescaledb_image_exists() {
    image_exists ${TS_IMAGE}
}

remove_build_container() {
    local container=${1:-${BUILD_CONTAINER_NAME}}
    docker rm -vf "$(docker ps -a -q -f name=${container} 2>/dev/null)" 2>/dev/null
}

fetch_postgres_build_image() {
    local image=${1:-${PG_IMAGE}}
    docker pull ${image}
}

create_postgres_build_image() {
    local image=${1:-${PG_IMAGE}}

    echo "Creating new PostgreSQL build image ${image}"
    # Run a Postgres container
    docker run -d --name ${BUILD_CONTAINER_NAME} --env POSTGRES_HOST_AUTH_METHOD=trust -v ${BASE_DIR}:/src postgres:${PG_IMAGE_TAG}

    # Install build dependencies
    docker exec -u root ${BUILD_CONTAINER_NAME} /bin/bash -c "apk add --no-cache --virtual .build-deps postgresql-dev gdb coreutils dpkg-dev gcc git libc-dev make cmake util-linux-dev diffutils libssl3 openssl-dev krb5-dev && mkdir -p /build/debug"
    docker commit -a $USER -m "TimescaleDB build base image version $PG_IMAGE_TAG" ${BUILD_CONTAINER_NAME} ${image}
    remove_build_container ${BUILD_CONTAINER_NAME}

    if ${PUSH_PG_IMAGE}; then
        docker push ${image}
    fi
}

run_postgres_build_image() {
    local image=${1:-${PG_IMAGE}}
    echo "Starting image ${image}"
    docker run -d --name ${BUILD_CONTAINER_NAME} -v ${BASE_DIR}:/src ${image}
}

build_timescaledb()
{
    echo "Building TimescaleDB image \"${TS_IMAGE}\" with USE_OPENSSL=${USE_OPENSSL} BUILD_TYPE=${BUILD_TYPE}"

    run_postgres_build_image ${PG_IMAGE}

    # Build and install the extension with debug symbols and assertions
    tar -c -C ${BASE_DIR} {cmake,src,sql,test,scripts,tsl,version.config,CMakeLists.txt,timescaledb.control.in} | docker cp - ${BUILD_CONTAINER_NAME}:/build/
    if ! docker exec -u root ${BUILD_CONTAINER_NAME} /bin/bash -c " \
        cd /build/debug \
        && git config --global --add safe.directory /src \
        && cmake -DGENERATE_DOWNGRADE_SCRIPT=${GENERATE_DOWNGRADE_SCRIPT} -DENABLE_DEBUG_UTILS=off -DUSE_OPENSSL=${USE_OPENSSL} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} /src \
        && make -j $(nproc) && make install \
        && echo \"shared_preload_libraries = 'timescaledb'\" >> /usr/local/share/postgresql/postgresql.conf.sample \
        && echo \"timescaledb.telemetry_level=off\" >> /usr/local/share/postgresql/postgresql.conf.sample \
        && cd / && rm -rf /build"
    then
      echo "Building timescaledb failed"
      return 1
    fi
    docker commit -a $USER -m "TimescaleDB development image" ${BUILD_CONTAINER_NAME} ${TS_IMAGE}
}

message_and_exit() {
    echo
    echo "Run 'docker run -d --name some-timescaledb -p 5432:5432 ${TS_IMAGE}' to launch"
    exit
}

remove_build_container

if timescaledb_image_exists; then
    echo "Image \"${TS_IMAGE}\" already exists."
    message_and_exit
fi


if ! postgres_build_image_exists; then
    if ! fetch_postgres_build_image "$@"; then
        create_postgres_build_image "$@" || exit 1
    fi
fi

build_timescaledb || exit 1

message_and_exit