#!/bin/sh -efu

# Copyright (C) 2025  Paul Wolneykien <manowar@altlinux.org>
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License Version 2
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
# 02110-1301, USA.

#shellcheck disable=SC2002

# See https://www.gnu.org/software/coreutils/faq/coreutils-faq.html#Sort-does-not-sort-in-normal-order_0021.
export LC_ALL=C

PROG="${0##*/}"
REALPROG="$(realpath "$0")"
PROGDIR="${REALPROG%/*}"
VERSION='0.4.6'
YEAR='2025'

setup_config() {
    cat <<EOF
# Distribution version (i. e. 10.2.1). Handy to use to define other
# variables below.
DISTROVER='${DISTROVER:-10.2.1}'

# Path to clone mkimage-profiles into. If not set then a TMPDIR-based
# dir is used. Make sure not to override the command-line option
# (i. e. use MKIPDIR="\${MKIPDIR:-...}" form).
MKIPDIR="\${MKIPDIR:-${MKIPDIR:-}}"

# URL to clone mkimage-profiles from.
MKIPURL='${MKIPURL:-git://git.altlinux.org/gears/m/mkimage-profiles.git}'

# Commit or tag to pull when cloning mkimage-profiles.
EOF
    if [ -n "${MKIPREF:-}" ]; then
	cat <<EOF
#MKIPREF="altsp-\$DISTROVER"
MKIPREF="$MKIPREF"
EOF
    else
	cat <<EOF
MKIPREF="altsp-\$DISTROVER"
EOF
    fi
    cat <<EOF

# SSH key to use when cloning mkimage-profiles.
MKIPKEY='${MKIPKEY:-}'

# Name of the distro target to build with mkimage-profiles.
DISTRO='${DISTRO:-alt-sp-common-update.tar}'

# Path for mkimage-profiles resulting files. If not set then
# TMPDIR-based dir is used. Make sure not to override the command-line
# option (i. e. use OUTDIR="\${OUTDIR:-...}" form).
OUTDIR="\${OUTDIR:-${OUTDIR:-}}"

# Path to checksum git repository. If not set or is empty then
# a TMPDIR-based dir is used.
CHKSUMDIR="${CHKSUMDIR:-\$HOME/checksumbot/repo}"

# URL to clone checksum git repository from (and also, to push
# new commits to).
CHKSUMURL='${CHKSUMURL:-git@gitlab.basealt.space:alt-checksum/checksums.git}'

# SSH key to use when cloning (and pushing) checksum git repository.
CHKSUMKEY='${CHKSUMKEY:-}'

# Checksum subtree path to extract from TAR distro and also the path
# to place the extracted checksums into the repo.
CHKSUMPATH='${CHKSUMPATH:-./chksum}'

# RPM package repository branch (i. e. p10, c10f2, ...).
BRANCH='${BRANCH:-c10f2}'

# Target architecture. Make sure not to override the command-line
# option (i. e. use ARCH="\${ARCH:-...}" form).
ARCH="\${ARCH:-${ARCH:-x86_64}}"

# APT configuration file for regular incremental updates. If empty
# then the system or user default is used.
APTCONF="${APTCONF:-\$HOME/checksumbot/apt.\$BRANCH.\$ARCH.conf}"

# APT configuration file for checksum branch initialization. If empty
# then \$APTCONF is used (not recommended).
APTRELEASE="${APTRELEASE:-\$HOME/checksumbot/apt.\$DISTROVER.\$ARCH.conf}"

# Path to the 'checksumdiff' script. If not specified, then \$PATH is
# used. Moreover, when 'checksumbot' is run from some user location,
# it tries to find 'checksumdiff' by the path relative to itself.
CHECKSUMDIFF='${CHECKSUMDIFF:-}'

# Path to the 'checksummerge' script. If not specified, then \$PATH is
# used. Moreover, when 'checksumbot' is run from some user location,
# it tries to find 'checksummerge' by the path relative to itself.
CHECKSUMMERGE='${CHECKSUMMERGE:-}'

# Base branch of the checksum git repository (it is used to initialize
# new release branches).
CHKSUMBASE='${CHKSUMBASE:-base}'

# The branch of the checksum git repository for regular updates.
# If not exists, then a new branch with the given name is initialized
# from \$CHKSUMBASE.
CHKSUMBRANCH="${CHKSUMBRANCH:-\$DISTROVER/\$ARCH}"

# Path to keep temporary (!) sensible data (in particular,
# temporary GNUPGHOME is made there). If not set or is empty
# then a TMPDIR-based dir is used.
PRIVDIR='${PRIVDIR:-}'

# GnuPG secret key to sign the resulting checksum commit with.
GPGKEY='${GPGKEY:-}'

# Set to nonzero to enable verbose mode. Make sure not to override
# the command-line option (i. e. use VERBOSE="\${VERBOSE:-...}"
# form).
VERBOSE=\${VERBOSE:-${VERBOSE:-1}}

# Set to nonzero to skip pushing to the checksum repository by default
# (can be overriden with --push command-line option. Make sure not to
# override the command-line option (i. e. use NOPUSH="\${NOPUSH:-...}"
# form). There is also --nopush option.
NOPUSH=\${NOPUSH:-${NOPUSH:-1}}

# Path to log file. If not set then the messages are printed to
# stderr. Make sure not to override the command-line option
# even if is empty (i. e. use LOGFILE="\${LOGFILE-...}" form).
LOGFILE="\${LOGFILE-${LOGFILE:-}}"

# Whether to include RPM package list files into the checksum
# repository.
INCLUDE_RPM_LISTS=${INCLUDE_RPM_LISTS:-1}
EOF
}

usage()
{
    [ "$1" = 0 ] || exec >&2
    cat <<EOF
Usage: $PROG [options] [-a ARCH -c CONFIG ]

Options:

    -a ARCH, --arch=ARCH    set \$ARCH environment variable to
                            the specified arch;

    -m MKIPDIR, --mkip=MKIPDIR    set \$MKIPDIR environment variable to
                                  the specified path;

    -r MKIPREF, --ref=MKIPREF     set \$MKIPREF environment variable to
                                  the specified value;

    -o OUTDIR, --out=OUTDIR    set \$OUTDIR environment variable to
                               the specified path;

    --cb=CHKSUMBRANCH          set the \$CHKSUMBRANCH environment
                               variable to the specified value;

    -l LOGFILE, --log=LOGFILE    set the \$LOGFILE environment variable to
                                 the specified path;

    -E, --nolog    output all messages to stderr (same as -l'');

    --nopush    do not push the updates (sets \$NOPUSH=1);

    --push    push the updates (sets \$NOPUSH=0);

    --force-update   update the existing checksum data using
                     checksummerge(1) utility;

    -v, --verbose    print additional informational messages
                     (\$VERBOSE=1);

    -q, --quiet      don't print informational messages (\$VERBOSE=0);

    -n, --dry-run    print the final configuration and exit;

    --setup    if specified before -c CONFIG instead of reading it
               writes it dumping the current and default values,
               then exit; otherwise -- dumps the current values
               to stdout and exit;

    -c CONFIG, --conf=CONFIG    read-in the configuration file
                                CONFIG (make sure not to override the
                                above environment variables!);

    -V, --version    print version information and exit;

    -h, --help    print this help info and exit.
EOF
    exit "${1:-0}"
}

TEMP="$(getopt -n "$PROG" -o a:m:r:o:l:Ec:vqnVh -l arch:,mkip:,ref:,out:,cb:,log:,nolog,setup,conf:,nopush,push,force-update,verbose,quiet,dry-run,version,help -- "$@")" || usage 1
eval set -- "$TEMP"

setup=0
dry_run=0
force_update=0
while :; do
    case "$1" in
	-a|--arch)
	    shift
	    ARCH="$1"
	    ;;
	-m|--mkip)
	    shift
	    MKIPDIR="$1"
	    ;;
	-r|--ref)
	    shift
	    MKIPREF="$1"
	    ;;
	-o|--out)
	    shift
	    OUTDIR="$1"
	    ;;
	--cb)
	    shift
	    CHKSUMBRANCH="$1"
	    ;;
	-l|--log)
	    shift
	    LOGFILE="$1"
	    ;;
	-E|--nolog)
	    LOGFILE=
	    ;;
	--nopush)
	    NOPUSH=1
	    ;;
	--push)
	    NOPUSH=0
	    ;;
	--setup)
	    setup=1
	    ;;
	-c|--config)
	    shift
	    if [ "${setup:-0}" -ne 0 ]; then
		setup_config >"$1"
		exit 0
	    fi
	    #shellcheck disable=SC1090
	    case "$1" in
		/*)
		    . "$1"
		    ;;
		*)
		    . "$(pwd)/$1"
		    ;;
	    esac
	    ;;
	--force-update)
	    force_update=1
	    ;;
	-v|--verbose)
	    VERBOSE=1
	    ;;
	-q|--quiet)
	    VERBOSE=0
	    ;;
	-n|--dry-run)
	    dry_run=1
	    ;;
	-V|--version)
	    cat <<EOF
$VERSION $YEAR
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.
EOF
	    exit 0
	    ;;
        -h|--help)
	    usage 0
            ;;
        --)
	    shift
	    break
            ;;
        *)
	    echo "$PROG: unrecognized option: $1" >&2
	    usage 1
            ;;
    esac
    shift
done

if [ "${setup:-0}" -ne 0 ]; then
    setup_config
    exit 0
fi

if [ $# -gt 0 ]; then
    echo "Unexpected arguments: $*" >&2
    exit 1
fi

exec 3>&2

if [ "${dry_run:-0}" -eq 0 ]; then
    if [ -n "${LOGFILE:-}" ]; then
	exec 2>>"$LOGFILE" 1>&2
	echo "-- $(date)" >&2
    fi
fi

with_verbose=
#shellcheck disable=SC2034
[ "${VERBOSE:-0}" -eq 0 ] || with_verbose=y
with_debug=
#shellcheck disable=SC2034
[ "${DEBUG:-0}" -eq 0 ] || with_debug=y

workdir=
gpgdir=
cleanup() {
    ret=$?
    if [ -n "$gpgdir" ]; then
	rm -rf "$gpgdir"
	[ "${VERBOSE:-0}" -eq 0 ] || \
	    echo "Removed $gpgdir." >&2
    fi
    if [ -n "${MKIPDIR:-}" ]; then
	if [ -d "$MKIPDIR" ]; then
	    if [ "${DEBUG:-0}" -eq 0 ]; then
		(
		    cd "$MKIPDIR"
		    verb make distclean >&2
		) ||:
		if [ "${delete_mkipdir:-0}" -ne 0 ]; then
		    rm -rf "$MKIPDIR"
		    [ "${VERBOSE:-0}" -eq 0 ] || \
			echo "Removed $MKIPDIR." >&2
		fi
	    fi
	fi
    fi
    if [ -n "$workdir" ]; then
	if [ "${DEBUG:-0}" -eq 0 ]; then
	    rm -rf "$workdir"
	    [ "${VERBOSE:-0}" -eq 0 ] || \
		echo "Removed $workdir." >&2
	fi
    fi
    if [ "${DEBUG:-0}" -ne 0 ]; then
	echo "DEBUG MODE: Workdir: $workdir" >&2
	if [ -n "${MKIPDIR:-}" ] && [ -d "$MKIPDIR" ]; then
	    echo "DEBUG MODE: Don't forget to cleanup mkimage-profiles temporary files! Use \`cd '$MKIPDIR' && make distclean\`." >&2
	fi
    fi
    if [ $ret -ne 0 ]; then
        if [ -n "${LOGFILE:-}" ]; then
	    echo "ERROR: See $LOGFILE for more details:" >&3
            tail "$LOGFILE" >&3
        fi
    fi
}
trap 'cleanup' EXIT
workdir="$(mktemp -d --tmpdir "$PROG.XXXX")"

MKIPDIR="${MKIPDIR:-$workdir/mkimage-profiles}"
OUTDIR="${OUTDIR:-$workdir/out}"
APTRELEASE="${APTRELEASE:-$APTCONF}"

which_here() {
    case "$PROGDIR" in
	/bin|/sbin|/usr/bin|/usr/sbin)
	    ;;
	*)
	    if [ -e "$PROGDIR"/../checksumgen/"$1" ]; then
		realpath -e "$PROGDIR"/../checksumgen/"$1"
		return
	    fi
	    ;;
    esac

    which "$1" 2>/dev/null
}

[ -n "${CHECKSUMDIFF:-}" ] || \
    CHECKSUMDIFF="$(which_here checksumdiff)" 2>/dev/null ||:
if [ -z "$CHECKSUMDIFF" ]; then
    echo "ERROR: The 'checksumdiff' utility not found!" >&2
    exit 1
fi

[ -n "${CHECKSUMMERGE:-}" ] || \
    CHECKSUMMERGE="$(which_here checksummerge)" 2>/dev/null ||:
if [ -z "$CHECKSUMMERGE" ]; then
    echo "ERROR: The 'checksummerge' utility not found!" >&2
    exit 1
fi

PRIVDIR="${PRIVDIR:-$workdir}"

if [ "${VERBOSE:-0}" -ne 0 ] || [ "${dry_run:-0}" -ne 0 ]; then
    cat <<EOF >&2
MKIPDIR:           ${MKIPDIR:-}
MKIPURL:           ${MKIPURL:-}
MKIPREF:           ${MKIPREF:-}
MKIPKEY:           ${MKIPKEY:-}
DISTRO:            ${DISTRO:-}
OUTDIR:            ${OUTDIR:-}
CHKSUMDIR:         ${CHKSUMDIR:-}
CHKSUMURL:         ${CHKSUMURL:-}
CHKSUMKEY:         ${CHKSUMKEY:-}
CHKSUMPATH:        ${CHKSUMPATH:-}
BRANCH:            ${BRANCH:-}
ARCH:              ${ARCH:-}
APTCONF:           ${APTCONF:-}
APTRELEASE:        ${APTRELEASE:-}
CHECKSUMDIFF:      ${CHECKSUMDIFF:-}
CHECKSUMMERGE:     ${CHECKSUMMERGE:-}
CHKSUMBASE:        ${CHKSUMBASE:-}
CHKSUMBRANCH:      ${CHKSUMBRANCH:-}
PRIVDIR:           ${PRIVDIR:-}
GPGKEY:            ${GPGKEY:-}
VERBOSE:           ${VERBOSE:-}
NOPUSH:            ${NOPUSH:-}
LOGFILE:           ${LOGFILE:-}
INCLUDE_RPM_LISTS: ${INCLUDE_RPM_LISTS:-0}
EOF
fi

if [ "${dry_run:-0}" -ne 0 ]; then
    exit 0
fi

assert() {
    if [ -z "$(eval echo "\${$1:-}")" ]; then
	echo "ERROR: \$$1 is not set or is empty!" >&2
	echo "It should probably be defined in a configuration file loaded with the -c command-line option. Use --setup to generate the configuration template." >&2
	exit 1
    fi
}

assert 'CHKSUMDIR'
assert 'CHKSUMURL'
assert 'ARCH'
assert 'BRANCH'
assert 'DISTRO'
assert 'CHKSUMPATH'
assert 'CHKSUMBASE'
assert 'CHKSUMBRANCH'

case "$DISTRO" in
    *.tar)
	;;
    *)
	echo "ERROR: Expect a TAR distribution (alt-sp-common-update.tar, for instance)." >&2
	exit 1
	;;
esac

if [ ! -d "$MKIPDIR" ]; then
    assert 'MKIPURL'
    assert 'MKIPREF'
    delete_mkipdir=1
fi

with_gitkey() {
    #shellcheck disable=SC3043
    local sshkey=
    sshkey="$1"; shift
    (
	if [ -n "$sshkey" ]; then
	    # shellcheck disable=SC2089
	    GIT_SSH_COMMAND="ssh -i '$sshkey' -o IdentitiesOnly=yes -o StrictHostKeyChecking=no"
	    # shellcheck disable=SC2090
	    export GIT_SSH_COMMAND
	fi

	"$@"
    )
}

packager=
if [ -n "${GPGKEY:-}" ]; then
    gpgdir="$(mktemp -d --tmpdir="${PRIVDIR:-$workdir}" "$PROG.GPG.XXXX")"
    chmod 0700 "$gpgdir"
    export GNUPGHOME="$gpgdir"
    gpg2 -q --import <"$GPGKEY"
    packager="$(gpg2 -K --with-colons | grep '^uid:' | head -1 | cut -d: -f10)"
else
    echo "WARNING: Using default GPG key." >&2
fi

lock() {
    [ "${VERBOSE:-0}" -eq 0 ] || echo "Trying to lock${2:+ $2}..." >&2
    flock -x "$1"
    [ "${VERBOSE:-0}" -eq 0 ] || echo "...Locked." >&2
}

verb() {
    if [ "${VERBOSE:-0}" -ne 0 ]; then
	(
	    set -x
	    "$@"
	)
    else
	"$@"
    fi
}

nover() {
    sed -e 's/-[^-]\+-[^-]\+\.[^.]\+\.rpm$//'
}

mkdir -p "$CHKSUMDIR"
#shellcheck disable=SC2094
(
    lock 9 "$CHKSUMDIR"

    new_branch=
    remote_branch=
    if [ -e "$CHKSUMDIR"/.git ] && (cd "$CHKSUMDIR" && git branch | grep -q "$CHKSUMBRANCH"); then
	new_branch=0 # found locally
    elif with_gitkey "${CHKSUMKEY:-}" git ls-remote -q --refs --heads "$CHKSUMURL" | grep -q "refs/heads/$CHKSUMBRANCH"; then
	new_branch=0 # found remotely
	remote_branch="$CHKSUMBRANCH"
    else
	new_branch=1 # target branch not found
	remote_branch="$CHKSUMBASE"
    fi

    if [ -z "$new_branch" ]; then
	echo "BUG! Branch selection logic seems to be broken." >&2
	exit 1
    fi

    if [ ! -e "$CHKSUMDIR"/.git ]; then
	with_gitkey "${CHKSUMKEY:-}" verb git clone --single-branch -b "$remote_branch" "$CHKSUMURL" "$CHKSUMDIR" >&2
    fi

    cd "$CHKSUMDIR"

    git remote set-url 'origin' "$CHKSUMURL"
    git remote set-url --push 'origin' "$CHKSUMURL"

    with_gitkey "${CHKSUMKEY:-}" verb git fetch 'origin' "$CHKSUMBASE":refs/remotes/origin/"$CHKSUMBASE" >&2

    if [ "$new_branch" -eq 0 ]; then
	if with_gitkey "${CHKSUMKEY:-}" git ls-remote -q --refs --heads "$CHKSUMURL" | grep -q "refs/heads/$CHKSUMBRANCH"; then
	    with_gitkey "${CHKSUMKEY:-}" verb git fetch 'origin' "$CHKSUMBRANCH":refs/remotes/origin/"$CHKSUMBRANCH" >&2
	    if git branch | grep -q "$CHKSUMBRANCH"; then
		verb git checkout "$CHKSUMBRANCH" >&2
		verb git merge --ff-only origin/"$CHKSUMBRANCH" >&2
	    else
		verb git checkout -b "$CHKSUMBRANCH" origin/"$CHKSUMBRANCH" >&2
	    fi
	elif git branch | grep -q "$CHKSUMBRANCH"; then
	    verb git checkout "$CHKSUMBRANCH" >&2
	else
	    echo "BUG! Branch selection logic seems to be broken." >&2
	    exit 1
	fi
	if git diff --quiet origin/"$CHKSUMBASE"; then
	    [ "${VERBOSE:-0}" -eq 0 ] || \
		echo "Branch $CHKSUMBRANCH already exists, but contains no additional commits comparing to $CHKSUMBASE. Switch to release mode." >&2
	    new_branch=1
	else
	    [ "${VERBOSE:-0}" -eq 0 ] || \
		echo "Going to make a regular update of the $CHKSUMBRANCH branch." >&2
	fi
    else
	# new branch
	verb git checkout -b "$CHKSUMBRANCH" origin/"$CHKSUMBASE" >&2
	[ "${VERBOSE:-0}" -eq 0 ] || \
	    echo "Going to make a new release with $CHKSUMBRANCH branch." >&2
    fi

    if [ "$(git status -u --porcelain | wc -l)" -ne 0 ]; then
	echo "ERROR: The checksum repository working tree is not clean!" >&2
	echo "Please, investigate $(realpath .)." >&2
	exit 1
    fi

    if [ -n "$packager" ]; then
	git config user.name "$(echo "$packager" | sed -e 's/^[[:space:]]*\(.*\)[[:space:]]<\([^>]\+\)>.*$/\1/')"
	git config user.email "$(echo "$packager" | sed -e 's/^[[:space:]]*\(.*\)[[:space:]]<\([^>]\+\)>.*$/\2/')"
	git config gpg.program /usr/bin/gpg2

	[ "${VERBOSE:-0}" -eq 0 ] || \
	    echo "Set committer to: $(git config user.name) <$(git config user.email)>." >&2
    fi

    cd ..

    if [ ! -d "$MKIPDIR" ]; then
	mkdir -p "$MKIPDIR"
	if [ "$(git --version | (read -r _ _ ver && rpmvercmp "$ver" '2.49.0'))" -ge 0 ]; then
	    with_gitkey "${MKIPKEY:-}" verb git -c advice.detachedHead=false clone --depth=1 --revision="$MKIPREF" "$MKIPURL" "$MKIPDIR" >&2
	else
	    with_gitkey "${MKIPKEY:-}" verb git clone --depth=1 "$MKIPURL" "$MKIPDIR" >&2
	fi
    fi

    apt_conf=
    if [ "$new_branch" -eq 0 ]; then
	apt_conf="${APTCONF:-}"
    else
	# new checksum release
	apt_conf="${APTRELEASE:-}"
	if [ "$apt_conf" = "{APTCONF:-}" ]; then
	    echo "WARNING! Using regular APT config for a new chksum release (not recommended)!" >&2
	fi
    fi

    if [ -n "${apt_conf:-}" ]; then
	if [ ! -e "$apt_conf" ]; then
	    echo "ERROR: APT configuration file $apt_conf is missing!" >&2
	    exit 1
	fi
    fi

    cd "$MKIPDIR"

    with_gitkey "${MKIPKEY:-}" verb git fetch origin "$MKIPREF" >&2
    verb git -c advice.detachedHead=false checkout 'FETCH_HEAD' >&2

    ret=0
    verb make ARCH="$ARCH" ${apt_conf:+APTCONF="$apt_conf"} ${with_debug:+DEBUG=1 REPORT=1} BRANCH="$BRANCH" IMAGEDIR="$OUTDIR" "$DISTRO" >&2 || ret=$?
    if [ $ret -ne 0 ]; then
        echo "Building the distro failed." >&2
	if [ -e build/build.log ]; then
	    echo "Here is the tail of the build.log:" >&2
            tail -20 build/build.log >&2
	fi
	exit $ret
    fi
    cd ..

    [ "${VERBOSE:-0}" -eq 0 ] || echo "Extracting the checksums..." >&2

    cd "$CHKSUMDIR"
    verb tar --overwrite -xf "$OUTDIR"/"${DISTRO%.tar}"-latest-"$ARCH".tar "$CHKSUMPATH"

    if [ "$new_branch" -eq 0 ]; then
	# checksum update
	[ "${VERBOSE:-0}" -eq 0 ] || echo "Processing the checksum update..." >&2

	git status -uno --porcelain | sed -n -e 's/^ M //p' | \
	    while read -r m; do
		cat "$m" >"$workdir"/update.chksum
		git checkout HEAD -- "$m"
		if [ "$force_update" -ne 0 ]; then
		    echo "WARNING! Making forced checksum data update! The existing base checksum data may change!" >&2
		    verb "$CHECKSUMMERGE" -E ${with_verbose:+-v} \
			 "$m" "$workdir"/update.chksum \
			 -f -o "$m"
		fi
		verb "$CHECKSUMDIFF" ${with_verbose:+-v} \
		     -f -r "$workdir"/_diff.report \
		     "$m" "$workdir"/update.chksum
		cat "$workdir"/_diff.report >&2
		cat "$workdir"/_diff.report >>"$workdir"/diff.report
	    done
    fi

    verb git add "$CHKSUMPATH" >&2

    if [ "${INCLUDE_RPM_LISTS:-0}" -ne 0 ]; then
	tarout="$OUTDIR"/"${DISTRO%.tar}"-latest-"$ARCH".tar
	mkdir -p 'list'
	verb tar -xf "$tarout" './.disk/pkglists/main/srpm.txt' --to-stdout | \
	     sort | tee list/srpm.list | \
	     nover | sort >list/srpm_names.list
	verb git add list/srpm.list
	verb git add list/srpm_names.list
	verb tar -xf "$tarout" './.disk/pkglists/main/rpm.txt' --to-stdout | \
	     sort | tee list/rpm.list | \
	     nover | sort >list/rpm_names.list
	verb git add list/rpm.list
	verb git add list/rpm_names.list
    fi

    message=
    if ! git status -uno --porcelain | grep -q '^[AM]'; then
	if [ "$new_branch" -eq 0 ]; then
	    message='No new or modified files after checksum update'
	    [ "${VERBOSE:-0}" -eq 0 ] || echo "$message." >&2
	else
	    echo "ERROR: No checksum files has been added to the new branch $CHKSUMBRANCH!" >&2
	    exit 1
	fi
    else
	if [ "$new_branch" -eq 0 ]; then
	    message="Updated $CHKSUMBRANCH checksums"
	else
	    message="New $CHKSUMBRANCH released"
	fi
	verb git commit -S -m "$message" >&2
    fi

    if [ "${NOPUSH:-0}" -eq 0 ]; then
	with_gitkey "${CHKSUMKEY:-}" verb git push -u 'origin' "$CHKSUMBRANCH" >&2
    else
	[ "${VERBOSE:-0}" -eq 0 ] || \
	    echo "Not pushing commit(s) as specified (\$NOPUSH=$NOPUSH)." >&2
    fi

    if [ "${VERBOSE:-0}" -ne 0 ] && [ -n "${LOGFILE:-}" ]; then
	echo "$message." >&3
	[ ! -e "$workdir"/diff.report ] || cat "$workdir"/diff.report >&3
	if [ "${INCLUDE_RPM_LISTS:-0}" -ne 0 ]; then
	    git show --oneline HEAD -- list/rpm_names.list \
		>"$workdir"/rpm_names.diff
	    if [ ! -s "$workdir"/rpm_names.diff ]; then
		echo "The set of RPM names has not changed since the last update." >&3
	    else
		cat "$workdir"/rpm_names.diff >&3
	    fi
	fi
    fi
) 9<"$CHKSUMDIR"
