#!/bin/bash

set -e

N_PARALLEL="${2:-1}"

WORKDIR=$HOME/diff-cov-workdir
DATE=$(date +%Y%m%d)

PG_REPO=https://github.com/postgres/postgres.git

LCOV_OUTPUT_DIR=${WORKDIR}/lcov-outputs
LCOV_HTML_OUTPUT_DIR=${WORKDIR}/lcov-html
LCOV_HTML_FINAL_DIR=$HOME/diff-output

OUTDIR=${WORKDIR}/out
POSTGRES_DIR=${WORKDIR}/postgres-bare
BASELINE_PG_DIR="${WORKDIR}/pg-baseline"
CURRENT_PG_DIR="${WORKDIR}/pg-current"

BASELINE_COVERAGE_FILE="${LCOV_OUTPUT_DIR}/lcov-${DATE}-baseline"
CURRENT_COVERAGE_FILE="${LCOV_OUTPUT_DIR}/lcov-${DATE}-current"

UNIVERSAL_DIFF_FILE="${WORKDIR}/universal_diff"

clear_dirs()
{
    printf "Clearing directories.\n"
    rm -rf ${OUTDIR} ${UNIVERSAL_DIFF_FILE} ${LCOV_OUTPUT_DIR}
    printf "Done.\n\n"
}

clone_postgres()
{
    if [ ! -d "${POSTGRES_DIR}" ]; then
        git clone --bare $PG_REPO $POSTGRES_DIR
    else
        (cd $POSTGRES_DIR ; git fetch --force)
    fi
}

setup_worktrees()
{
    pushd ${POSTGRES_DIR}

    BASELINE_COMMIT_HASH=$(git branch --list "*REL_*_STABLE*" --format="%(refname) %(objectname)" | sort -k1r | head -1 | cut -d" " -f2)
    BASELINE_COMMIT_DATE=$(git show -s --format=%ci ${BASELINE_COMMIT_HASH})

    if [ -e $BASELINE_PG_DIR ]; then
	git worktree remove --force $BASELINE_PG_DIR
    fi
    git worktree add $BASELINE_PG_DIR $BASELINE_COMMIT_HASH

    CURRENT_COMMIT_HASH=$(git rev-parse HEAD)
    CURRENT_COMMIT_DATE=$(git show -s --format=%ci ${CURRENT_COMMIT_HASH})
    
    if [ -e $CURRENT_PG_DIR ]; then
	git worktree remove --force $CURRENT_PG_DIR
    fi
    git worktree add $CURRENT_PG_DIR $BASELINE_COMMIT_HASH

    popd
}

generate_unidiff()
{
    pushd ${POSTGRES_DIR}
    printf "Generating universal diff file.\n\n"
    git diff --relative --src-prefix="${BASELINE_PG_DIR}/" --dst-prefix="${CURRENT_PG_DIR}/" ${BASELINE_COMMIT_HASH} ${CURRENT_COMMIT_HASH} > ${UNIVERSAL_DIFF_FILE}
    printf "Done.\n\n"
    popd
}

build_postgres_meson()
{
    POSTGRES_BUILD_OPTIONS=(
        --wipe
        --clearcache
        -Db_coverage=true
        -Dcassert=true
        -Dinjection_points=true
        -Dtap_tests=enabled
        # xid_wraparound and ldap tests don't work on github actions
        -DPG_TEST_EXTRA="kerberos ssl load_balance libpq_encryption wal_consistency_checking oauth"
        --buildtype=debug
    )

    pg_dir="$2"
    build_dir="${pg_dir}_build"

    rm -rf ${build_dir}
    printf "Building Postgres to ${build_dir} by using meson. Commit hash is ${1}\n"
    $(cd ${pg_dir} && git reset -q --hard ${1})
    meson setup "${POSTGRES_BUILD_OPTIONS[@]}" "${build_dir}" ${pg_dir}
    meson compile -C ${build_dir}
    meson test -C ${build_dir} || true
    printf "Done building and testing.\n\n"
}

# Takes commit hash argument as $1.
run_lcov()
{
    pg_dir="$2"
    build_dir="${pg_dir}_build"

    LCOV_OPTIONS=(
        --ignore-errors "empty,empty,negative,negative,inconsistent,inconsistent,gcov,gcov"
        --all
        --capture
        --quiet
        --parallel ${N_PARALLEL}
        --filter range
        # for some reason this does not suffice, --rc branch_coverage=1 is required
        --branch-coverage
        --rc branch_coverage=1
        --include "**${pg_dir}/**"
        --directory "${build_dir}"
        -o ${1}
    )

    printf "Running lcov.\n"
    mkdir -p ${LCOV_OUTPUT_DIR}
    lcov "${LCOV_OPTIONS[@]}"
    printf "Done.\n\n"
}

# Takes commit hash argument as $1.
run_genhtml()
{
    GENHTML_OPTIONS=(
        --ignore-errors "inconsistent,range,path"
        --parallel ${N_PARALLEL}
        --legend
        --num-spaces 4
        --hierarchical
        --show-navigation
        --show-proportion
        --branch-coverage
        --rc branch_coverage=1
        --date-bins 1,7,30,360
        --title "${BASELINE_COMMIT_HASH} vs ${CURRENT_COMMIT_HASH}"
        --current-date "${CURRENT_COMMIT_DATE}"
        --baseline-date "${BASELINE_COMMIT_DATE}"
        --annotate-script /usr/share/lcov/support-scripts/gitblame
        --baseline-file ${BASELINE_COVERAGE_FILE}
        --diff-file ${UNIVERSAL_DIFF_FILE}
        --output-directory ${LCOV_HTML_OUTPUT_DIR}
        ${CURRENT_COVERAGE_FILE}
        # genhtml: ERROR: unexpected branch TLA UNC for count 0
        # --show-details
    )

    printf "Running genhtml to generate HTML report at ${LCOV_HTML_OUTPUT_DIR}.\n"
    mkdir -p ${LCOV_HTML_OUTPUT_DIR}
    genhtml "${GENHTML_OPTIONS[@]}"
    printf "Done.\n\n"
}

get_baseline_coverage_file()
{
    printf "Generating latest release's coverage file.\n"
    build_postgres_meson ${BASELINE_COMMIT_HASH} ${BASELINE_PG_DIR}
    run_lcov $BASELINE_COVERAGE_FILE ${BASELINE_PG_DIR}
    printf "Latest release's coverage file is generated now.\n\n"
}

get_current_coverage_file()
{
    printf "Generating current coverage file.\n"
    build_postgres_meson ${CURRENT_COMMIT_HASH} ${CURRENT_PG_DIR}
    run_lcov ${CURRENT_COVERAGE_FILE} ${CURRENT_PG_DIR}
    printf "Current coverage file is generated now.\n\n"
}

clear_dirs
clone_postgres
setup_worktrees
generate_unidiff

get_baseline_coverage_file
get_current_coverage_file

run_genhtml

mv -f ${LCOV_HTML_FINAL_DIR} ${LCOV_HTML_FINAL_DIR}.old || true
mv -f ${LCOV_HTML_OUTPUT_DIR} ${LCOV_HTML_FINAL_DIR}
