#!/bin/bash
# License: Unspecified

shopt -s extglob

#!/hint/bash
# This may be included with or without `set -euE`

# License: Unspecified

[[ -z ${_INCLUDE_COMMON_SH:-} ]] || return 0
_INCLUDE_COMMON_SH="$(set +o|grep nounset)"

set +u +o posix
# shellcheck disable=1091
. /usr/share/makepkg/util.sh
$_INCLUDE_COMMON_SH

# Avoid any encoding problems
export LANG=C

shopt -s extglob

# check if messages are to be printed using color
if [[ -t 2 ]]; then
	colorize
else
	# shellcheck disable=2034
	declare -gr ALL_OFF='' BOLD='' BLUE='' GREEN='' RED='' YELLOW=''
fi

stat_busy() {
	local mesg=$1; shift
	# shellcheck disable=2059
	printf "${GREEN}==>${ALL_OFF}${BOLD} ${mesg}...${ALL_OFF}" "$@" >&2
}

stat_done() {
	# shellcheck disable=2059
	printf "${BOLD}done${ALL_OFF}\n" >&2
}

_setup_workdir=false
setup_workdir() {
	[[ -z ${WORKDIR:-} ]] && WORKDIR=$(mktemp -d --tmpdir "${0##*/}.XXXXXXXXXX")
	_setup_workdir=true
	trap 'trap_abort' INT QUIT TERM HUP
	trap 'trap_exit' EXIT
}

cleanup() {
	if [[ -n ${WORKDIR:-} ]] && $_setup_workdir; then
		rm -rf "$WORKDIR"
	fi
	exit "${1:-0}"
}

abort() {
	error 'Aborting...'
	cleanup 255
}

trap_abort() {
	trap - EXIT INT QUIT TERM HUP
	abort
}

trap_exit() {
	local r=$?
	trap - EXIT INT QUIT TERM HUP
	cleanup $r
}

die() {
	(( $# )) && error "$@"
	cleanup 255
}

##
#  usage : lock( $fd, $file, $message, [ $message_arguments... ] )
##
lock() {
	# Only reopen the FD if it wasn't handed to us
	if ! [[ "/dev/fd/$1" -ef "$2" ]]; then
		mkdir -p -- "$(dirname -- "$2")"
		eval "exec $1>"'"$2"'
	fi

	if ! flock -n "$1"; then
		stat_busy "${@:3}"
		flock "$1"
		stat_done
	fi
}

##
#  usage : slock( $fd, $file, $message, [ $message_arguments... ] )
##
slock() {
	# Only reopen the FD if it wasn't handed to us
	if ! [[ "/dev/fd/$1" -ef "$2" ]]; then
		mkdir -p -- "$(dirname -- "$2")"
		eval "exec $1>"'"$2"'
	fi

	if ! flock -sn "$1"; then
		stat_busy "${@:3}"
		flock -s "$1"
		stat_done
	fi
}

##
#  usage : lock_close( $fd )
##
lock_close() {
	local fd=$1
	# https://github.com/koalaman/shellcheck/issues/862
	# shellcheck disable=2034
	exec {fd}>&-
}

##
# usage: pkgver_equal( $pkgver1, $pkgver2 )
##
pkgver_equal() {
	if [[ $1 = *-* && $2 = *-* ]]; then
		# if both versions have a pkgrel, then they must be an exact match
		[[ $1 = "$2" ]]
	else
		# otherwise, trim any pkgrel and compare the bare version.
		[[ ${1%%-*} = "${2%%-*}" ]]
	fi
}

##
#  usage: find_cached_package( $pkgname, $pkgver, $arch )
#
#    $pkgver can be supplied with or without a pkgrel appended.
#    If not supplied, any pkgrel will be matched.
##
find_cached_package() {
	local searchdirs=("$PWD" "$PKGDEST") results=()
	local targetname=$1 targetver=$2 targetarch=$3
	local dir pkg pkgbasename name ver rel arch r results

	for dir in "${searchdirs[@]}"; do
		[[ -d $dir ]] || continue

		for pkg in "$dir"/*.pkg.tar?(.?z); do
			[[ -f $pkg ]] || continue

			# avoid adding duplicates of the same inode
			for r in "${results[@]}"; do
				[[ $r -ef $pkg ]] && continue 2
			done

			# split apart package filename into parts
			pkgbasename=${pkg##*/}
			pkgbasename=${pkgbasename%.pkg.tar?(.?z)}

			arch=${pkgbasename##*-}
			pkgbasename=${pkgbasename%-"$arch"}

			rel=${pkgbasename##*-}
			pkgbasename=${pkgbasename%-"$rel"}

			ver=${pkgbasename##*-}
			name=${pkgbasename%-"$ver"}

			if [[ $targetname = "$name" && $targetarch = "$arch" ]] &&
					pkgver_equal "$targetver" "$ver-$rel"; then
				results+=("$pkg")
			fi
		done
	done

	case ${#results[*]} in
		0)
			return 1
			;;
		1)
			printf '%s\n' "${results[0]}"
			return 0
			;;
		*)
			error 'Multiple packages found:'
			printf '\t%s\n' "${results[@]}" >&2
			return 1
	esac
}


# Source makepkg.conf; fail if it is not found
if [[ -r '/etc/makepkg.conf' ]]; then
	# shellcheck source=makepkg-x86_64.conf
	source '/etc/makepkg.conf'
else
	die '/etc/makepkg.conf not found!'
fi

# Source user-specific makepkg.conf overrides
if [[ -r "${XDG_CONFIG_HOME:-$HOME/.config}/pacman/makepkg.conf" ]]; then
	# shellcheck source=/dev/null
	source "${XDG_CONFIG_HOME:-$HOME/.config}/pacman/makepkg.conf"
elif [[ -r "$HOME/.makepkg.conf" ]]; then
	# shellcheck source=/dev/null
	source "$HOME/.makepkg.conf"
fi

if [[ ! -f PKGBUILD ]]; then
	die 'This must be run in the directory of a built package.'
fi

# shellcheck source=PKGBUILD.proto
. ./PKGBUILD
if [[ ${arch[0]} == 'any' ]]; then
	CARCH='any'
fi

STARTDIR=$(pwd)
TEMPDIR=$(mktemp -d --tmpdir checkpkg-script.XXXX)

for _pkgname in "${pkgname[@]}"; do
	comparepkg=$_pkgname
	pkgurl=
	target_pkgver=$(get_full_version "$_pkgname")
	if ! pkgfile=$(find_cached_package "$_pkgname" "$target_pkgver" "$CARCH"); then
		die 'tarball not found for package: %s' "${_pkgname}-$target_pkgver"
	fi

	ln -s "$pkgfile" "$TEMPDIR"

	if (( $# )); then
		case $1 in
			/*|*/*)
				pkgurl=file://$(readlink -m "$1") ;;
			*.pkg.tar*)
				pkgurl=$1 ;;
			'')
				;;
			*)
				comparepkg=$1 ;;
		esac
		shift
	fi
	[[ -n $pkgurl ]] || pkgurl=$(pacman -Spdd --print-format '%l' --noconfirm "$comparepkg") ||
		die "Couldn't download previous package for %s." "$comparepkg"

	oldpkg=${pkgurl##*/}

	if [[ ${oldpkg} = "${pkgfile##*/}" ]]; then
		die "The built package (%s) is the one in the repo right now!" "$_pkgname"
	fi

	if [[ $pkgurl = file://* || ( $pkgurl = /* && -f $pkgurl ) ]]; then
		ln -s "${pkgurl#file://}" "$TEMPDIR/$oldpkg"
	elif [[ -f "$PKGDEST/$oldpkg" ]]; then
		ln -s "$PKGDEST/$oldpkg" "$TEMPDIR/$oldpkg"
	elif [[ -f "$STARTDIR/$oldpkg" ]]; then
		ln -s "$STARTDIR/$oldpkg" "$TEMPDIR/$oldpkg"
	else
		curl -fsLC - --retry 3 --retry-delay 3 -o "$TEMPDIR/$oldpkg" "$pkgurl"
	fi

	bsdtar tf "$TEMPDIR/$oldpkg" | sort > "$TEMPDIR/filelist-$_pkgname-old"
	bsdtar tf "$pkgfile" | sort > "$TEMPDIR/filelist-$_pkgname"

	sdiff -s "$TEMPDIR/filelist-$_pkgname-old" "$TEMPDIR/filelist-$_pkgname"

	find-libprovides "$TEMPDIR/$oldpkg" 2>/dev/null | sort > "$TEMPDIR/libraries-$_pkgname-old"
	find-libprovides "$pkgfile" 2>/dev/null | sort > "$TEMPDIR/libraries-$_pkgname"
	if ! diff_output="$(sdiff -s "$TEMPDIR/libraries-$_pkgname-old" "$TEMPDIR/libraries-$_pkgname")"; then
		msg "Sonames differ in $_pkgname!"
		echo "$diff_output"
	else
		msg "No soname differences for %s." "$_pkgname"
	fi
done

msg "Files saved to %s" "$TEMPDIR"
