#!/bin/sh

# script to add apt.postgresql.org to sources.list.d

# Copyright (C) 2013-2023 Christoph Berg <myon@debian.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# The full text of the GPL is distributed as in
# /usr/share/common-licenses/GPL-2 on Debian systems.

SOURCESLIST="/etc/apt/sources.list.d/pgdg.sources"
TYPES="deb"
COMPONENTS="main"
PGDG="pgdg"

# variables imported from https://git.postgresql.org/gitweb/?p=pgapt.git;a=blob;f=pgapt.conf
# checked out in $HOME/apt.postgresql.org/; run "make" to update
PG_BETA_VERSION="16"
PG_DEVEL_VERSION="17"
PG_REPOSITORY_DISTS="sid trixie bookworm bullseye buster mantic lunar kinetic jammy focal bionic"
PG_ARCHIVE_DISTS="sid trixie bookworm bullseye buster stretch jessie wheezy squeeze lenny etch mantic lunar kinetic jammy impish hirsute groovy focal eoan disco cosmic bionic zesty xenial wily utopic saucy precise lucid"

while getopts "c:f:h:ipstv:y" opt ; do
    case $opt in
        c) COMPONENTS="main $OPTARG" ;; # make these extra components available
        f) SOURCESLIST=$OPTARG ;; # sources.list filename to write to
        h) HOST="$OPTARG" ;; # hostname to use in sources.list
        i) INSTALL="yes" ;; # install packages for version given with -v
        p) PURGE="yes" ;; # purge existing postgresql packages
        s) TYPES="deb deb-src" ;; # include source repository as well
        t) PGDG="pgdg-testing" ;; # use *-pgdg or *-pgdg-testing
        v) PGVERSION="$OPTARG" ;; # set up sources.list to use this version (useful for beta/devel packages)
        y) ;; # don't ask for confirmation
        *) exit 5 ;;
    esac
    YES="yes" # don't ask for confirmation if any option is given
done
# shift away args
shift $((OPTIND - 1))
# check options
if [ "$INSTALL" ] && [ -z "$PGVERSION" ]; then
    echo "With -i, a version to install must be provided (-v)"
    exit 1
fi

# codename from command line
CODENAME="$1"
# parse os-release
if [ -z "$CODENAME" ] && [ -f /etc/os-release ]; then
    . /etc/os-release
    if [ "$VERSION_CODENAME" ]; then # added in buster/xenial
        CODENAME="$VERSION_CODENAME"
    else
        # Debian: VERSION="7.0 (wheezy)"
        # Ubuntu: VERSION="13.04, Raring Ringtail"
        #         VERSION="18.04.1 LTS (Bionic Beaver)"
        CODENAME=$(echo $VERSION | sed -ne 's/.*(\(.*\)).*/\1/') # works on Debian only
    fi
fi
# try lsb_release
if [ -z "$CODENAME" ] && command -v lsb_release >/dev/null; then
    CODENAME=$(lsb_release -cs 2>/dev/null)
fi
# guess from sources.list
if [ -z "$CODENAME" ] && [ -f /etc/apt/sources.list ]; then
    CODENAME=$(grep '^deb ' /etc/apt/sources.list | head -n1 | awk '{ print $3 }')
fi
# complain if no result yet
if [ -z "$CODENAME" ]; then
    cat <<EOF
Could not determine the distribution codename. Please report this as a bug to
pgsql-pkg-debian@postgresql.org. As a workaround, you can call this script with
the proper codename as parameter, e.g. "$0 squeeze".
EOF
    exit 1
fi

# errors are non-fatal above
set -eu

if [ "${HOST:-}" ]; then
    :
elif echo "$PG_REPOSITORY_DISTS" | grep -qw "$CODENAME"; then
    # known distribution on apt.postgresql.org
    HOST="apt.postgresql.org"
elif echo "$PG_ARCHIVE_DISTS" | grep -qw "$CODENAME"; then
    # known distribution on apt.postgresql.org
    HOST="apt-archive.postgresql.org"
else # unknown distribution, verify on the web
    HOST="apt.postgresql.org"
	DISTURL="https://$HOST/pub/repos/apt/dists/"
	if [ -x /usr/bin/curl ]; then
	    DISTHTML=$(curl -s $DISTURL || :)
	elif [ -x /usr/bin/wget ]; then
	    DISTHTML=$(wget --quiet -O - $DISTURL || :)
	fi
	if [ "${DISTHTML:-}" ]; then
	    if ! echo "$DISTHTML" | grep -q "$CODENAME-$PGDG"; then
		cat <<EOF
Your system is using the distribution codename $CODENAME, but $CODENAME-$PGDG
does not seem to be a valid distribution on
$DISTURL

We abort the installation here. If you want to use a distribution different
from your system, you can call this script with an explicit codename, e.g.
"$0 precise".

For more information, refer to https://wiki.postgresql.org/wiki/Apt
or ask on the mailing list for assistance: pgsql-pkg-debian@postgresql.org
EOF
		exit 1
	    fi
	fi
fi

cat <<EOF
This script will enable the PostgreSQL APT repository on $HOST on
your system. The distribution codename used will be $CODENAME-$PGDG.

EOF

if [ -z "${YES:-}" ]; then
    echo -n "Press Enter to continue, or Ctrl-C to abort."
    read enter
    echo
fi

# keyring needs to be readable for apt
umask 022
# prefer .gpg keyring from postgresql-common
KEYRING="/usr/share/postgresql-common/pgdg/apt.postgresql.org.gpg"
# otherwise, use the .asc key
test -e $KEYRING || KEYRING="/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc"
echo "Using keyring $KEYRING"
# write .asc key to disk if not yet present
if ! test -e $KEYRING; then
    mkdir -p /usr/share/postgresql-common/pgdg
    cat > $KEYRING <<EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----


Gtz3cydIohvNO9d90+29h0eGEDYti7j7maHkBKUAwlcPvMg5m3Y=
=DA1T
-----END PGP PUBLIC KEY BLOCK-----
EOF
fi

for version in ${PGVERSION:-}; do
    # devel version comes from *-pgdg-snapshot (with lower default apt pinning priority)
    if dpkg --compare-versions $version ge "${PG_DEVEL_VERSION:-999}"; then
        COMPONENTS="$COMPONENTS $version" # devel component is likely empty, but add it to be sure
        DEVEL_COMPONENT="${DEVEL_COMPONENT:-} $version"
        PIN="-t $CODENAME-pgdg-snapshot"
    # beta version needs a different component
    elif dpkg --compare-versions $version ge "${PG_BETA_VERSION:-999}"; then
        COMPONENTS="$COMPONENTS $version"
    fi

    # select packages to install
    PACKAGES="${PACKAGES:-} postgresql-$version postgresql-server-dev-$version"
    case $version in
        8*|9*) PACKAGES="$PACKAGES postgresql-contrib-$version" ;;
    esac
done

echo "Writing $SOURCESLIST ..."
cat > $SOURCESLIST <<EOF
Types: $TYPES
URIs: https://$HOST/pub/repos/apt
Suites: $CODENAME-$PGDG
Components: $COMPONENTS
Signed-By: $KEYRING
EOF

# write a separate section for devel without main so we don't include all of snapshot
if [ "${DEVEL_COMPONENT:-}" ]; then
cat >> $SOURCESLIST <<EOF

Types: $TYPES
URIs: https://$HOST/pub/repos/apt
Suites: $CODENAME-pgdg-snapshot
Components: ${DEVEL_COMPONENT# }
Signed-By: $KEYRING
EOF
fi

if [ "$SOURCESLIST" = "/etc/apt/sources.list.d/pgdg.sources" ]; then
    # remove pgdg.list when upgrading to pgdg.sources
    rm -vf /etc/apt/sources.list.d/pgdg.list /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg
fi

echo
echo "Running apt-get update ..."
apt-get update

cat <<EOF

You can now start installing packages from $HOST.

Have a look at https://wiki.postgresql.org/wiki/Apt for more information;
most notably the FAQ at https://wiki.postgresql.org/wiki/Apt/FAQ
EOF

# remove/install packages
export DEBIAN_FRONTEND=noninteractive
if [ "${PURGE:-}" ]; then
    echo
    echo "Purging existing PostgreSQL packages ..."
    apt-get -y purge postgresql-client-common
fi
if [ "${INSTALL:-}" ]; then
    echo
    echo "Installing packages for PostgreSQL $PGVERSION ..."
    apt-get -y -o DPkg::Options::=--force-confnew \
        install ${PIN:-} $PACKAGES
fi
