#!/bin/bash

# Copyright: 2010-2022, gregor herrmann <gregoa@debian.org>
#            2014-2015, Salvatore Bonaccorso <carnil@debian.org>
#            2015-2023, intrigeri <intrigeri@debian.org>
#            2019, Clément Hermann <nodens@nodens.org>
# Licensed under the same terms as Perl (Artistic | GPL-1+)

# to be run from source directory

# environment:
# - BUILDDIR, defaults to ".."
# - ARCH, defaults to arch of .changes file

# functions #

echo_info() {
	local green reset
	green=$(tput setaf 2)
	reset=$(tput sgr0)
	echo -e "${green}I: $*${reset}"
}

echo_warning() {
	local yellow reset
	yellow=$(tput setaf 3)
	reset=$(tput sgr0)
	echo -e "${yellow}W: $*${reset}"
}

echo_error() {
	local red reset
	red=$(tput setaf 1)
	reset=$(tput sgr0)
	echo -e "${red}E: $*${reset}"
}

notify() {
	local command=$1
	local urgency=${2:-normal}
	if [ -x /usr/bin/notify-send ] && [ -n "$DISPLAY" ] && [ -n "$command" ] ; then
		notify-send -u "$urgency" -t 5000 "$command finished" "$(dpkg-parsechangelog | grep -E '^(Source|Version)')"
	fi
}

# main #

BUILDDIR=${BUILDDIR:-".."}
if [ ! -d "$BUILDDIR" ] ; then
	echo_error "Build directory \"$BUILDDIR\" does not exist.\n" \
	           "  Maybe you forgot to set the BUILDDIR variable?\n" \
		   "  Exiting ..."
	exit 1
fi

rm -rf "$BUILDDIR"/*obsolete*
rm -f  "$BUILDDIR"/*.dsc.asc

PACKAGE=$(dpkg-parsechangelog -S Source)
VERSION=$(dpkg-parsechangelog -S Version | perl -pe 's|^\d+:||')

if [ -z "$ARCH" ] ; then
	# Since we use a ls sorting option, implementing this without ls|grep
	# would require quite some efforts.
	# shellcheck disable=SC2010
	CHANGES=$(ls -1rt "$BUILDDIR/${PACKAGE}_${VERSION}"_*.changes \
		      | grep -v -E '_source\.changes$' \
		      | tail -n 1)
	ARCH=$(basename "${CHANGES##"$BUILDDIR/${PACKAGE}_${VERSION}"_}" .changes)
else
	CHANGES="$BUILDDIR/${PACKAGE}_${VERSION}_${ARCH}.changes"
fi

BUILD="$BUILDDIR/${PACKAGE}_${VERSION}_${ARCH}.build"
DSC="$BUILDDIR/${PACKAGE}_${VERSION}.dsc"

if [ ! -r "$CHANGES" ] || ! [ -r "$DSC" ] ; then
	echo_error "E: Can't read \"$CHANGES\" or \"$DSC\".\n" \
	            "  Is BUILDDIR set correctly: \"$BUILDDIR\"?\n" \
	            "  Exiting ..."
	exit 1
fi

FORMAT=$(grep ^Format: "$DSC" | cut -f2 -d" ")

if [ -x /usr/bin/lintian ]; then
	echo "lintian:"
	echo "========"
	#lintian -i -I --show-overrides --pedantic --color auto --no-tag-display-limit "$CHANGES"
	#~/.lintianrc, lintian 2.5.1; tag-display-limit=0 since 2.5.63; --output-width since 2.105.0
	LINTIANVERSION=$(dpkg-query -f '${Version}\n' -W lintian)
	if dpkg --compare-versions "$LINTIANVERSION" ge 2.105.0 ; then
		lintian --output-width 80 "$CHANGES"
	else
		lintian "$CHANGES"
	fi
fi

if [ -x /usr/bin/blhc ] && [ -r "$BUILD" ] && ! grep -E -q "^Architecture: all$" "$DSC" ; then
	echo "blhc:"
	echo "====="
	blhc --buildd "$BUILD"
elif [ ! -x /usr/bin/blhc ]; then
	echo "bhlc isn't installed, skipping."
fi
echo

if [ -x /usr/bin/duck ] ; then
	echo "duck:"
	echo "====="
	duck
else
	echo "duck isn't installed, skipping."
fi
echo

read -r -n 1 -p "debc? y/N " DEBC
if [ "$DEBC" = "y" ]; then 
	debc -a "$ARCH" "$CHANGES" | less
fi
echo

read -r -n 1 -p "piuparts? y/N " PIU
if [ "$PIU" = "y" ]; then
	PIUPARTSLOG="${CHANGES%.changes}_piuparts.log"
	CHROOT=
	# default is --no-minimize; add --minimize for pbuilder/cowbuilder, not for schroot
	[ -f /var/cache/pbuilder/base.tar.gz ] && CHROOT="--pbuilder --minimize"
	[ -f /var/cache/pbuilder/base.tgz ] && CHROOT="--pbuilder --minimize"
	[ -d /var/cache/pbuilder/base.cow ] && CHROOT="--existing-chroot /var/cache/pbuilder/base.cow --minimize"
	# no eatmydata in chroot; proxy not resolvable
	if [ -x /usr/bin/schroot ] && schroot -l | grep -q default; then
		CHROOT="--schroot default --no-eatmydata --proxy="
	fi
	CHANGESPIU="${CHANGES%.changes}_piuparts.changes"
	if grep -qE "^Binary: .+-dbgsym.*$" "$CHANGES" ; then
		grep -vE '\-dbgsym_.+\.deb$' "$CHANGES" > "$CHANGESPIU"
	else
		cp "$CHANGES" "$CHANGESPIU"
	fi
	# log-level: error < info < debug <  dump
	echo
	sudo /usr/sbin/piuparts \
		# Deliberately word splitting CHROOT
		# shellcheck disable=SC2086
		$CHROOT -t "${TMPDIR:-/tmp}" \
		--warn-on-others --warn-on-debsums-errors --skip-logrotatefiles-test \
		--log-level=debug --log-file="$PIUPARTSLOG" \
		"$CHANGESPIU"
	rm "$CHANGESPIU"
	notify piuparts
fi
echo

read -r -n 1 -p "reprotest? y/N " REPRO
if [ "$REPRO" = "y" ]; then
	REPROTESTLOG="${CHANGES%.changes}_reprotest.log"
	if [ -x /usr/bin/schroot ] && schroot -l | grep -q default; then
		REPROTEST_VIRT_SERVER=schroot
		REPROTEST_VIRT_SERVER_ARGS=default
	fi
	if [ -n "$REPROTEST_VIRT_SERVER" ]; then
		REPROTESTVERSION=$(dpkg-query -f '${Version}\n' -W reprotest)
		if dpkg --compare-versions "$REPROTESTVERSION" ge 0.7.4 ; then
			REPROTESTPARAMS="--variations=+all,-user_group,-domain_host,-fileordering,-time --verbosity 1 . "
		else
			REPROTESTPARAMS="auto --verbosity 1 . "
		fi
		echo
		# Deliberately word splitting variables
		# shellcheck disable=SC2086
		env -u TMPDIR CCACHE_DIR=/tmp/.ccache reprotest $REPROTESTPARAMS -- $REPROTEST_VIRT_SERVER $REPROTEST_VIRT_SERVER_ARGS 2>&1 | \
			tee $REPROTESTLOG
		notify reprotest
	else
		echo_warning "Could not find reprotest virtualization server."
	fi
fi
echo

if grep -q 'Testsuite: autopkgtest' debian/control || [ -f debian/tests/control ]; then
	read -r -n 1 -p "autopkgtest? y/N " AUTOPKGTEST
	if [ "$AUTOPKGTEST" = "y" ]; then
		AUTOPKGTESTLOG="${CHANGES%.changes}_autopkgtest.log"
		if ! [ -v AUTOPKGTEST_VIRT_SERVER ]; then
			if [ -x /usr/bin/schroot ] && schroot -l | grep -q default; then
				AUTOPKGTEST_VIRT_SERVER=schroot
				AUTOPKGTEST_VIRT_SERVER_ARGS=default
			fi
		fi
		if [ -n "$AUTOPKGTEST_VIRT_SERVER" ]; then
			echo
			# Deliberately word splitting variables
			# shellcheck disable=SC2086
			autopkgtest "$CHANGES" --log-file="$AUTOPKGTESTLOG" --shell-fail $AUTOPKGTEST_ARGS -- \
				$AUTOPKGTEST_VIRT_SERVER $AUTOPKGTEST_VIRT_SERVER_ARGS
			SUCCESS=$?
			case $SUCCESS in
				0)
					URGENCY=normal
					;;
				2)
					echo_warning "autopkgtest: at least one test was skipped (or at least one flaky test failed)."
					URGENCY=normal
					;;
				8)
					echo_warning "autopkgtest: no tests in this package, or all non-superficial tests were skipped."
					URGENCY=normal
					;;
				*)
					echo_error "autopkgtest: failed ($SUCCESS)."
					URGENCY=critical
					;;
			esac
			exec 0</dev/tty
			notify autopkgtest $URGENCY
		else
			echo_warning "Could find no autopkgtest virtualization server."
		fi
		# TODO:
		# since 3.7 we get colours but only without --log-file=. and on STDERR.
		# See https://git-tails.immerda.ch/tails/tree/run_test_suite?h=testing
		# for an example of how to get colours on the terminal,
		# while still creating a log file without control chars.
	fi
fi
echo

PKGVER=$(echo "${PACKAGE}-${VERSION}" | perl -pe 's;^(.+)(?:-.+)$;$1;')
AUTOPATCH="debian/patches/debian-changes-${VERSION}"
DIFFGZ="$BUILDDIR/${PACKAGE}_${VERSION}.diff.gz"
DEBGZ="$BUILDDIR/${PACKAGE}_${VERSION}.debian.tar.gz"
DEBBZ2="$BUILDDIR/${PACKAGE}_${VERSION}.debian.tar.bz2"
DEBXZ="$BUILDDIR/${PACKAGE}_${VERSION}.debian.tar.xz"
[ -e "$DEBGZ" ] || DEBGZ="$DEBBZ2"
[ -e "$DEBGZ" ] || DEBGZ="$DEBXZ"

if [ "$FORMAT" = "1.0" ] && [ -e "$DIFFGZ" ] && zgrep -E "^\+\+\+ " "$DIFFGZ" | grep -q -v "$PKGVER/debian"; then
	echo
	echo_warning "Changes in .diff.gz outside debian/!"
	read -r -n 1 -p "View .diff.gz? y/N " VIEWDIFFGZ
	if [ "$VIEWDIFFGZ" = "y" ]; then
		filterdiff -z -x "$PKGVER/debian/*" "$DIFFGZ" | colordiff | /usr/bin/less -R
	fi
	echo
	echo_info "Maybe: mkdir -p debian/patches && diff2patches $DIFFGZ"
	echo
elif [ "$FORMAT" = "3.0" ] && [ -e "$DEBGZ" ] && tar tvf "$DEBGZ" | grep -q "$AUTOPATCH"; then
	echo
	echo_warning "Automatically created patch in .debian.tar.gz/.bz2/.xz!"
	read -r -n 1 -p "View .debian.tar.gz/.bz2/.xz? y/N " VIEWDEBGZ
	if [ "$VIEWDEBGZ" = "y" ]; then
		tar xf "$DEBGZ" "$AUTOPATCH" --to-stdout | colordiff | /usr/bin/less -R
	fi
	echo
	echo_info "Maybe: tar xf $DEBGZ $AUTOPATCH"
	echo
else
	read -r -n 1 -p "Ready for upload? y/N " UPLOAD
	if [ "$UPLOAD" = "y" ]; then
		echo
		cat "$CHANGES"
		echo
		BUILDINFO="${CHANGES%%.changes}".buildinfo
		if grep -q "\.u\?deb" "$CHANGES"; then
			read -r -n 1 -p "Strip binary .(u)debs? y/N " STRIPDEBS
			if [ "$STRIPDEBS" = "y" ]; then
				SOURCEONLYCHANGES="${CHANGES%%_"$ARCH".changes}_sourceonly.changes"
				mergechanges --source "$CHANGES" "$CHANGES" > "$SOURCEONLYCHANGES"
				if [ -f "$BUILDINFO" ]; then
					if [ -x /usr/bin/changestool ]; then
						SOURCEONLYBUILDINFO="${BUILDINFO%%_"$ARCH".buildinfo}_sourceonly.buildinfo"
						cp "$BUILDINFO" "$SOURCEONLYBUILDINFO"
						changestool "$SOURCEONLYCHANGES" add "$SOURCEONLYBUILDINFO"
					else
						echo
						echo_warning "Can't find changestool (from reprepro package)."
					fi
				fi
				echo
				cat "$SOURCEONLYCHANGES"
				CHANGES="$SOURCEONLYCHANGES"
			else
				echo
				# Fallback to question if only want to strip arch:any (u)debs
				read -r -n 1 -p "Strip arch:any .(u)debs? y/N " STRIPARCHANY
				if [ "$STRIPARCHANY" = "y" ]; then
					ALLONLYCHANGES="${CHANGES%%_"$ARCH".changes}_allonly.changes"
					mergechanges --indep "$CHANGES" "$CHANGES" > "$ALLONLYCHANGES"
					if [ -f "$BUILDINFO" ]; then
						if [ -x /usr/bin/changestool ]; then
							ALLONLYBUILDINFO="${BUILDINFO%%_"$ARCH".buildinfo}_allonly.buildinfo"
							cp "$BUILDINFO" "$ALLONLYBUILDINFO"
							changestool "$ALLONLYCHANGES" add "$ALLONLYBUILDINFO"
						else
							echo
							echo_warning "Can't find changestool (from reprepro package)."
						fi
					fi
					echo
					cat "$ALLONLYCHANGES"
					CHANGES="$ALLONLYCHANGES"
				fi
			fi
			echo
		fi
		debsign "$CHANGES"
		echo
		echo dput "$(readlink -f "$CHANGES")"
	fi
	echo
fi
