#!/bin/sh

set -eu

this="$(readlink -e "${0}")"

# assign defaults
project_dir="$(dirname "$(dirname "${this}")")"
debian_tag="${DEBIAN_TAG:-sid}"

usage() {
    cat << EOF
Usage: $(basename "${this}") [OPTION]... [ACTION]
Run tests or create package in a podman (or docker) container

Options:
    -h                print this usage and exit
    -C PROJECT_DIR    change to PROJECT_DIR (default: ${project_dir})
    -t DEBIAN_TAG     debian release tag (default: ${debian_tag})
    -c CONTAINER_CMD  container runner command (default: podman)

Actions:
    help       print this usage and exit
    package    create debian package artifacts
    test       run tests (default)

Example:
    $(basename "${this}") -C ~/code/git-buildpackage -t trixie package
EOF
}

die() { { echo "ERROR: ${*}"; usage; } >&2; exit 1; }

# convenience wrapper
container_build() {
    ${container_cmd} build \
        --force-rm="${DOCKER_BUILD_FORCE_RM:-false}" \
        --no-cache="${DOCKER_BUILD_NO_CACHE:-false}" \
        "${@}"
}

# take path to project dir; build docker image for base
base_build() {
    (
        cd "${project_dir}"
        [ -f .gitignore ] && cat .gitignore
        [ -f .gitmodules ] && sed -nr 's|\s+path = (.+)|\1|gp' .gitmodules
        cat <<EOF
${this##"${PWD}"/}
*.buildinfo
*.changes
*.deb
*.dsc
*.tar.xz
.dockerignore
.git*
EOF
    ) > "${project_dir}/.dockerignore"
    container_build \
        --pull="${DOCKER_BUILD_PULL:-false}" \
        --build-arg="FROM_IMAGE=debian:${debian_tag}" \
        -t "gbp-base:${debian_tag}" -f- "${project_dir}" <<'EOF'
ARG FROM_IMAGE
FROM ${FROM_IMAGE}
ENV DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true
WORKDIR /workdir/project
RUN set -euvx \
&& export DEBIAN_FRONTEND=noninteractive \
&& apt-get update -y \
&& apt-get -y --no-install-recommends upgrade \
&& apt-get -y --no-install-recommends install \
build-essential devscripts equivs \
&& apt-get clean
COPY debian debian
RUN mk-build-deps -r -i debian/control -t 'apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends'
# To avoid constantly invalidating previous container layers, run the slow
# dependency installation early and copy files (along with any changed files)
# later
COPY . .
RUN groupadd luser && useradd -g luser luser && chown -R luser:luser ..
USER luser
EOF
    rm -vf "${project_dir}/.dockerignore"
}


# run tests
gbp_test() {
    base_build
    # Build another image, this time with .git so that the tests.component tests
    # aren't skipped, and with additional packages needed to run the full test
    # suite.
    container_build \
        -t "gbp-test:${debian_tag}" -f- "${project_dir}" <<EOF
FROM gbp-base:${debian_tag}
USER 0:0
RUN git config --global safe.directory '*'
VOLUME /workdir/project
RUN set -euvx \
&& export DEBIAN_FRONTEND=noninteractive \
&& apt-get update -y \
&& apt-get -y --no-install-recommends upgrade \
&& apt-get -y --no-install-recommends install curl flake8 \
&& apt-get clean
EOF
    for L in C.UTF-8 C; do
        ${container_cmd} run --rm -ie"TEST_LOCALE=${L}" \
        --mount="type=bind,source=${project_dir},target=/workdir/project" \
        "gbp-test:${debian_tag}" sh <<'EOF'
set -euvx
export CI=true
make all+net
make -C docs
EOF
    done
}

# create debian package artifacts, copy to host
gbp_package() {
    base_build
    ${container_cmd} run --rm -iu0:0 \
        --mount="type=bind,source=${PWD},target=/mnt/host-volume" \
        "gbp-base:${debian_tag}" sh <<EOF
set -euvx
dpkg-buildpackage -j$(nproc) -sa -us -uc
find .. -maxdepth 1 -mindepth 1 -type f \
    -exec chown -v $(id -u):$(id -g) {} + \
    -a -exec cp -vat /mnt/host-volume {} +
EOF
}

while getopts ":hC:t:c:" opt; do
    case $opt in
        h) usage; exit 0;;
        C) project_dir="$(readlink -e "${OPTARG}")"
            [ -d "${project_dir}" ] || die "bad project dir ${OPTARG}";;
        t) debian_tag="${OPTARG}";;
        c) container_cmd="${OPTARG}";;
        :) die "missing argument: -${OPTARG}";;
        \?) die "bad option: -${OPTARG}";;
    esac
done

# Set default container command
container_cmd="${container_cmd:-podman}"

# Set default container command value if none set
case "${container_cmd}" in
    docker|podman) ;;
    *) die "container command is expected to be one of 'docker' or 'podman'" ;;
esac

shift $((OPTIND - 1))
case "${1:-test}" in
    'help') usage; exit 0;;
    'test') gbp_test; exit ${?};;
    'package') gbp_package; exit ${?};;
    *) die "bad action: ${1}";;
esac
