#!/bin/sh

source /etc/makepkg.conf
if [ -e "${XDG_CONFIG_HOME}/pacman/makepkg.conf" ]; then
	source "${XDG_CONFIG_HOME}/pacman/makepkg.conf"
elif [ -e ~/.makepkg.conf ]; then
	source ~/.makepkg.conf
fi
source /etc/conf.d/eworm-repo
source /usr/lib/eworm/noroot
source /usr/lib/eworm/colors
source /usr/lib/eworm/nice

# There may be some implications where gpg-agent starts X11 pinentry. So
# unset DISPLAY and have ncurses pinentry.
unset DISPLAY

function help() {
	echo "usage: ${0} [OPTIONS]"
	echo
	echo "where OPTIONS are:"
	echo " -a ARCH     build for architecture ARCH"
	echo " -b PACKAGE  build PACKAGE from ABS"
	echo " -c          check AUR state (outdated and orphan)"
	echo " -C CHROOT   build in chroot CHROOT-ARCH"
	echo " -g          generate checksums when building locally"
	echo " -h          show this help"
	echo " -H          build on host, not in chroot"
	echo " -l PACKAGE  build local PACKAGE"
	echo " -n          do not apply patches"
	echo " -o          offload to build server"
	echo " -p          publish to AUR"
	echo " -r          rebuild even if it seems up to date"
	echo " -u PACKAGE  build PACKAGE from AUR"
	echo
	echo "Default is to build local package if PKGBUILD exists."
}

ABSPACKAGE=""
ANYARCH=()
ARCH="x86_64"
NOCHROOT=0
CHECKAUR=0
CHROOT=""
CURRENTDIR=""
FORCEREBUILD=0
GENERATECHECKSUM=0
MD5NEW=""
MD5OLD=""
MODE=""
NOPATCH=0
OFFLOAD=0
PACKAGE=""
PKGVER=""
PUBLISH=0

while getopts "a:b:cC:ghHl:nopru:" opt; do
	case ${opt} in
		a)
			case "${OPTARG}" in
				x86_64)
					ARCH="x86_64"
					;;
				*)
					echo "Architecture '${OPTARG}' is unknown." >&2
					help
					exit 1
					;;
			esac
			;;
		b)
			if [ -n "${MODE}" ]; then
				echo "Looks like you gave too many options..." >&2
				help
				exit 1
			fi
			MODE="ABS"
			ABSPACKAGE="${OPTARG}"
			;;
		c)
			CHECKAUR=1
			;;
		C)
			CHROOT="${OPTARG}"
			;;
		g)
			GENERATECHECKSUM=1
			;;
		h)
			help
			exit 0
			;;
		H)
			NOCHROOT=1
			;;
		l)
			MODE="local"
			PACKAGE="${OPTARG}"
			;;
		n)
			NOPATCH=1
			;;
		o)
			OFFLOAD=1
			;;
		p)
			PUBLISH=1
			;;
		r)
			FORCEREBUILD=1
			;;
		u)
			if [ -n "${MODE}" ]; then
				echo "Looks like you gave too many options..." >&2
				help
				exit 1
			fi
			MODE="AUR"
			PACKAGE="${OPTARG}"
			;;
	esac
done

if [ -z "${PACKAGER}" ]; then
	echo "Please edit /etc/makepkg.conf, \${XDG_CONFIG_HOME}/pacman/makepkg.conf"
	echo "(${XDG_CONFIG_HOME}/pacman/makepkg.conf) or ~/.makepkg.conf and add a PACKAGER entry." >&2
	exit 1
fi

if [ -z "${GPGKEY}" ]; then
	echo "Please edit /etc/makepkg.conf, \${XDG_CONFIG_HOME}/pacman/makepkg.conf"
	echo "(${XDG_CONFIG_HOME}/pacman/makepkg.conf) or ~/.makepkg.conf and add a GPGKEY entry." >&2
	exit 1
fi

TMPFILE="$(mktemp -d --tmpdir=/tmp/ .$(basename ${0})-${$}-XXXXXX)"

if [ -z "${ARCH}" ]; then
	# CARCH should be defined in makepkg.conf
	ARCH="${CARCH}"
fi

# Prepare real build directory in ${TMPFILE}
# when leaving the case switch we should be in a directory containing a PKGFILE
case "${MODE}" in
	ABS)
		# build ABS package
		echo 'The old ABS via rsync is no longer accessible:' >&2
		echo 'https://www.archlinux.org/news/deprecation-of-abs/' >&2
		echo
		echo 'This feature is currently not available.' >&2
		exit 1
		;;
	AUR)
		# build AUR package
		if [ -z "${PACKAGE}" ]; then
			echo "Please give package name!" >&2
			help
			rmdir ${TMPFILE}
			exit 1
		fi

		if [ -d "${LOCALDIR}/${PACKAGE}" ]; then
			echo -e "Directory ${bldylw}'${PACKAGE}' exists${default} in ${LOCALDIR}, aborting." >&2
			rmdir ${TMPFILE}
			exit 1
		fi

		if [ ! -s ${BASEDIR}/aur.${ARCH} ] || ! grep -E -q " ${PACKAGE}( |$)" ${BASEDIR}/aur.${ARCH}; then
			echo "x ${PACKAGE}" >> ${BASEDIR}/aur.${ARCH}
		fi

		if [ ${CHECKAUR} -eq 1 ]; then
			repo-check -p "${PACKAGE}"
		fi

		echo -ne "AUR package ${bldwht}${PACKAGE}${default} (${ARCH}): "

		if [ -d "${SYNCDIR}/${PACKAGE}" ]; then
			git -C "${SYNCDIR}/${PACKAGE}" pull
		else
			git clone https://aur.archlinux.org/${PACKAGE}.git "${SYNCDIR}/${PACKAGE}"
			mkdir -p "${SYNCDIR}/${PACKAGE}/.git/info/"
			ln -sf /usr/share/devtools/git.conf.d/template/info/exclude "${SYNCDIR}/${PACKAGE}/.git/info/exclude"
		fi

		SHA1NEW="$(git -C "${SYNCDIR}/${PACKAGE}" rev-parse HEAD)"
		read SHA1OLD X LASTCHROOT <<< $(grep -E " ${PACKAGE}( |$)" < ${BASEDIR}/aur.${ARCH})
		CHROOT="${CHROOT:-${LASTCHROOT}}"

		if [ ${FORCEREBUILD} -eq 1 ]; then
			echo "Rebuilding even without new commits."
		else
			if [ "${SHA1NEW}" = "${SHA1OLD}" ]; then
				echo -e "Already ${bldgrn}up to date${default}."
				rmdir ${TMPFILE}
				exit 0
			fi

			echo -e "${bldylw}New commit${default}, rebuilding."
		fi

		cp -a "${SYNCDIR}/${PACKAGE}" "${TMPFILE}/${PACKAGE}"

		sed -i 's|^M$||' ${TMPFILE}/${PACKAGE}/PKGBUILD
		;;
	*)
		# build local package
		if [ "${MODE}" = "local" ]; then
			if [ -z "${PACKAGE}" ]; then
				echo "Please give package name!" >&2
				help
				rmdir ${TMPFILE}
				exit 1
			fi

			if [ ! -s "${LOCALDIR}/${PACKAGE}/PKGBUILD" ]; then
				echo -e "File ${PACKAGE}/PKGBUILD does not exist in ${LOCALDIR}, aborting." >&2
				rmdir ${TMPFILE}
				exit 1
			fi

			cd "${LOCALDIR}/${PACKAGE}/"
		else # build local package in current directory
			if [ ! -s "PKGBUILD" ]; then
				echo "Nothing to build. What did you wish to do?" >&2
				help
				rmdir ${TMPFILE}
				exit 1
			fi
			PACKAGE="$(basename $(pwd))"
		fi

		if grep -q source.tar.bz2 PKGBUILD && [ -d files ]; then
			echo "Found source tarball, building a new one and forcing to regenerate checksums."
			rm -f source.tar.bz2
			tar -c files/ | bzip2 > source.tar.bz2
			GENERATECHECKSUM=1
		fi

		if [ ${GENERATECHECKSUM} -eq 1 ]; then
			updpkgsums
		fi

		CURRENTDIR="$(pwd)"
		cp -a ${CURRENTDIR}/ ${TMPFILE}/${PACKAGE}
		;;
esac

cd ${TMPFILE}/${PACKAGE}

if [ ${NOPATCH} -eq 1 ]; then
	echo "Requested not to patch package... Skipping even if patches exist."
else
	if [ -f ${PATCHDIR}/${PACKAGE}.patch ]; then
		echo "Additional patch found... Applying."
		if ! patch -Np1 < ${PATCHDIR}/${PACKAGE}.patch; then
			echo "Failed to apply patch." >&2
			exit 1
		fi
	fi

	if [ -f ${PATCHDIR}/${PACKAGE}.sed ]; then
		echo "Sed script file found... Applying to PKGBUILD."
		if ! sed -i -f ${PATCHDIR}/${PACKAGE}.sed PKGBUILD; then
			echo "Failed to run sed script." >&2
			exit 1
		fi
	fi
fi

if [ ${FORCEREBUILD} -eq 1 ]; then
	echo "Changing package release version..."
	sed -i "/^pkgrel=[0-9]\+$/s/$/.$(date +%Y%m%d%H%M)/" PKGBUILD
fi

if [ -n "${SRCDEST}" ]; then
	GITNAME="$(grep -E '^_gitname=' PKGBUILD | cut -d'=' -f2 | tr -d "'\"")"
	if [ -n "${GITNAME}" ]; then
		if [ -d "${SRCDEST}/${GITNAME}" ]; then
			echo "Found local git dir, cloning from there."
			mkdir -p ${TMPFILE}/${PACKAGE}/src
			git clone ${SRCDEST}/${GITNAME} ${TMPFILE}/${PACKAGE}/src/${GITNAME}
		fi
	fi
fi

if [ "${NOCHROOT}" -eq 1 ]; then
	if ! makepkg --nosign --clean; then
		echo "Failed to build on host. Files are left in ${TMPFILE}" >&2
		exit 1
	fi
elif [ "${OFFLOAD}" -eq 1 ]; then
	if ! pkgctl build --offload; then
		echo "Failed to offload build to server." >&2
		exit 1
	fi
else
	if [ ! -d /var/lib/archbuild/${CHROOT:-extra}-${ARCH}/ ]; then
		echo "The chroot ${CHROOT:-extra}-${ARCH}/ does not exist, building dummmy package."
		( mkdir ${TMPFILE}/dummy/
		  cd ${TMPFILE}/dummy/
		  cp /usr/share/eworm-repo/PKGBUILD PKGBUILD
		  if [[ "${CHROOT%%-*}" == 'multilib' ]]; then
			${CHROOT}-build
		  else
			${CHROOT:-extra}-${ARCH}-build
		  fi )
	fi

	if ! makechrootpkg -r /var/lib/archbuild/${CHROOT:-extra}-${ARCH}/ -u -d ${GITDIR} -d ${HGDIR} -d ${BZRDIR}; then
		echo "Failed to build in chroot. Files are left in ${TMPFILE}" >&2
		exit 1
	fi
fi

for PKG in $(find -type f -regex '.*\.pkg\.tar\(\.\(gz\|bz2\|xz\|zst\|lrz\|lzo\|Z\|lz4?\)\)?'); do
	if [[ "${PKG}" =~ '-debug-' ]]; then
		echo "Skipping debug package." >&2
		continue
	fi

	# sign package
	while ! gpg -b --default-key "${GPGKEY}" "${PKG}"; do
		echo "Failed to sign package. <ENTER> to retry, <Ctrl>-<c> to cancel." >&2
		read || break
	done

	PKGARCH="$(bsdtar --to-stdout -xf "${PKG}" ".PKGINFO" 2>&1 | grep 'arch =' | cut -d' ' -f3)"
	PKGVER="$(bsdtar --to-stdout -xf "${PKG}" ".PKGINFO" 2>&1 | grep 'pkgver =' | cut -d' ' -f3)"
	FILE="$(basename ${PKG})"

	if [ ! -s "${PKG}.sig" ]; then
		echo "Package signature does not exist." >&2
		exit 1
	fi

	if ! mv -f "${PKG}"{,.sig} ${REPODIR}/${PKGARCH}/; then
		echo "Could not move package and/or signature to repository." >&2
		exit 1
	fi

	if [ "${PKGARCH}" == "any" ]; then
		ANYARCH=('x86_64')

		for ARCHI in ${ANYARCH[@]}; do
			ln -sf ../any/${FILE}{,.sig} ${REPODIR}/${ARCHI}/
		done
	else
		ANYARCH=("${PKGARCH}")
	fi

	for ARCHI in ${ANYARCH[@]}; do
		if ! repo-add --verify --key "${GPGKEY}" --sign ${REPODIR}/${ARCHI}/${REPONAME}.db.tar.gz ${REPODIR}/${ARCHI}/${FILE}; then
			echo "Could not add to database file." >&2
			exit 1
		fi
	done

	date +"%s" > ${REPODIR}/lastupdate

	# try to link to local cache dir, but do not complain on error
	rm -f /var/cache/pacman/pkg/${FILE}
	if ! ln ${REPODIR}/${PKGARCH}/${FILE}{,.sig} /var/cache/pacman/pkg/ >/dev/null 2>/dev/null; then
		ln -sr ${REPODIR}/${PKGARCH}/${FILE}{,.sig} /var/cache/pacman/pkg/ >/dev/null 2>/dev/null
	fi
done

case "${MODE}" in
	AUR)
		sed -i "/ ${PACKAGE}\( \|\$\)/c ${SHA1NEW} ${PACKAGE} ${CHROOT:-extra}" ${BASEDIR}/aur.${ARCH}
		;;
	*)
		if grep -q "pkgver()" ${CURRENTDIR}/PKGBUILD; then
			sed -i -e "/^pkgver=/c pkgver=${PKGVER%-*}" \
				-e "/^pkgrel=/c pkgrel=${PKGVER#*-}" ${CURRENTDIR}/PKGBUILD
		fi

		if [ ${PUBLISH} -eq 1 ]; then
			cd ${CURRENTDIR}/

			makepkg --printsrcinfo > .SRCINFO

			if git status >/dev/null 2>/dev/null; then
				git add PKGBUILD .SRCINFO

				for FILE in *.install $(tr -d ' \t' < .SRCINFO | grep -E '^source(|_x86_64)=' | cut -d= -f2); do
					if [ -e "${FILE}" ]; then
						git add "${FILE}"
				fi
				done

				git commit -m "commit ${PACKAGE} ${PKGVER}"
				if git remote 2>/dev/null | grep -q 'origin'; then
					git push
				fi
			fi
		fi
esac

cd
rm -rf ${TMPFILE}/{dummy,${PACKAGE}}
rmdir ${TMPFILE}

repo-sync
