#! /bin/sh
# pkgpoke helper that wraps the apt-get calls pkgpoke is permitted to make
# via sudo. Restricts the surface area of the sudoers rule to "update" and
# "install <pkg>=<version>" with no other arguments or side-effects, so
# even if the wildcard in /etc/sudoers.d/pkgpoke matched something
# unexpected the wrapper itself would refuse to run it.
set -e

# Run apt non-interactively so the service never blocks waiting on a
# debconf prompt
export DEBIAN_FRONTEND=noninteractive

case "$1" in
    update)
        # No additional arguments allowed
        if [ "$#" -ne 1 ]; then
            echo "usage: pkgpoke-apt update" >&2
            exit 2
        fi
        exec /usr/bin/apt-get update
        ;;
    install)
        # Exactly one extra argument of the form pkg=version
        if [ "$#" -ne 2 ]; then
            echo "usage: pkgpoke-apt install <pkg>=<version>" >&2
            exit 2
        fi
        case "$2" in
            *=*) ;;
            *) echo "argument must be of the form pkg=version" >&2; exit 2 ;;
        esac
        # --allow-downgrades so explicit version pins can move both
        # directions; --force-conf{old,def} keeps operator-modified config
        # files in place when packages with conffile prompts are installed
        exec /usr/bin/apt-get install -y \
            --allow-downgrades \
            -o "Dpkg::Options::=--force-confold" \
            -o "Dpkg::Options::=--force-confdef" \
            "$2"
        ;;
    install-detached)
        # Used only when pkgpoke is asked to update itself. Dispatches the
        # apt-get install into a transient systemd service so that when
        # dpkg's postinst calls `systemctl try-restart pkgpoke.service`
        # mid-install, only the running pkgpoke gets killed — the install
        # process is in a separate cgroup owned by PID 1 and continues to
        # completion. Running the install inside pkgpoke.service's own
        # cgroup would have systemd tear it down along with us, leaving
        # dpkg in a half-installed state.
        if [ "$#" -ne 2 ]; then
            echo "usage: pkgpoke-apt install-detached <pkg>=<version>" >&2
            exit 2
        fi
        case "$2" in
            *=*) ;;
            *) echo "argument must be of the form pkg=version" >&2; exit 2 ;;
        esac
        # --no-block returns immediately after submitting the unit so the
        # caller (and the response back to CI) doesn't sit waiting on the
        # install. --collect garbage-collects the unit on exit so the
        # operator never has to clean up failed transient units by hand.
        # The fixed unit name causes a second concurrent self-update to
        # fail fast rather than trample the first.
        exec /usr/bin/systemd-run \
            --no-block \
            --collect \
            --unit=pkgpoke-self-update.service \
            --description="pkgpoke self-update apt-get install" \
            /usr/lib/pkgpoke/pkgpoke-apt install "$2"
        ;;
    *)
        echo "unknown subcommand: ${1:-<empty>}" >&2
        exit 2
        ;;
esac
