#!/usr/bin/env bash
# (c) 2019-2026 Michał Górny <mgorny@gentoo.org>
# SPDX-License-Identifier: GPL-2.0-or-later

shopt -s extglob
shopt -s nullglob

check_valid() {
	if [[ ${1} != *.ebuild ]]; then
		echo "Incorrect filename: ${1}"
		exit 1
	fi

	filename=${1##*/}
	version=$(patom -F '%{fullver}' "=category/${1%.ebuild}")
	if [[ -z ${version} ]]; then
		echo "Incorrect filename: ${1}"
		exit 1
	fi
}

from_arg_to_filename() {
	local arg=${1}

	if [[ ! -f ${arg} ]]; then
		local ebuilds
		mapfile -t ebuilds < <(printf '%s\n' ${arg} | sort -r -V)
		set -- "${ebuilds[@]}"

		# skip live ebuilds
		while [[ ${1} == *9999* ]]; do shift; done
		[[ -n ${1} ]] && arg=${1}
	fi

	echo "${arg}"
}

version_arg_to_filename() {
	local arg=${1}
	local reference=${2}

	reference=${reference%.ebuild}
	reference=${reference%-r+([0-9])}
	reference=${reference%_p+([0-9])}

	if [[ ${arg} == +* ]]; then
		refv=.${reference##*-}
		suffix=

		while [[ ${arg} == *.* ]]; do
			refv=${refv%.*}
			suffix=.${arg##*.}${suffix}
			arg=${arg%.*}
		done

		oldv=${refv##*.}
		arg=${refv%.*}.$(( oldv + ${arg#+} ))${suffix}
		arg=${arg#.}
	fi

	# a version number?
	if [[ ${arg} != *.ebuild ]]; then
		arg=${reference%-*}-${arg}.ebuild
	fi

	echo "${arg}"
}

commit=
diff=1
edit=
edit_early=
dekeyword=1
manifest=1
from='*.ebuild'
to=+1

posargs=()
for arg; do
	case ${arg} in
		-c|--commit)
			commit=1
			;;
		-D|--no-diff)
			diff=
			;;
		-M|--no-manifest)
			manifest=
			;;
		-E|--edit-early)
			edit_early=1
			;;
		-e|--edit)
			edit=1
			;;
		-h|--help)
			echo "Usage: ${0} [<options>] [<source>] [<target>]"
			echo "  <source> can be:"
			echo "    a filename: foo-1.2.3.ebuild"
			echo "    a pattern, the newest match will be used: foo-*.ebuild"
			echo "    if unspecified, defaults to *.ebuild"
			echo "  <target> can be:"
			echo "    a filename: foo-1.2.4.ebuild (only if source is specified)"
			echo "    a version number: 1.2.4"
			echo "    an increment to the last component: +1"
			echo "    an increment + subsequent components: +1.1 -> 1.3.1"
			echo "    if unspecified, defaults to +1"
			echo "  <options> can include:"
			echo "    -E, --edit-early: edit before updating the Manifest"
			echo "    -M, --no-manifest: skip updating the Manifest"
			echo "    -D, --no-diff: skip diffing via pkgdiff-mg"
			echo "    -e, --edit: edit the ebuild after the above"
			echo "    -c, --commit: commit the ebuild via pkgcommit . -sS --bump"
			exit 0
			;;
		-s|--stable)
			dekeyword=
			;;
		*)
			posargs+=( "${arg}" )
			;;
	esac
done

set -- "${posargs[@]}"
case ${#} in
	0)
		;;
	1)
		[[ -f ${1} ]] && from=${1} || to=${1}
		;;
	2)
		from=${1}
		to=${2}
		;;
	*)
		echo "Usage: pkgbump [-c] [-D] [-M] [-e] [-s] [<from>] [<to>]" >&2
		exit 1
		;;
esac

from=$(from_arg_to_filename "${from}")
check_valid "${from}"
to=$(version_arg_to_filename "${to}" "${from}")
check_valid "${to}"

set -e -x

scriptdir=${BASH_SOURCE%/*}
user_snippet_dir=/etc/pkgbump.d
system_snippet_dir=${scriptdir}/../lib/pkgbump.d

cp "${from}" "${to}"
"${scriptdir}"/copybump "${to}"
if [[ ${dekeyword} ]]; then
	ekeyword ~all "${to}"
fi

for snippet in "${system_snippet_dir}"/*; do
	snippet_name=${snippet##*/}
	if [[ ! -f ${user_snippet_dir}/${snippet_name} ]]; then
		"${SHELL}" "${snippet}" "${from}" "${to}"
	fi
done
for snippet in "${user_snippet_dir}"/*; do
	"${SHELL}" "${snippet}" "${from}" "${to}"
done


if [[ ${edit_early} ]]; then
	${EDITOR:-vim} "${to}"
fi

# tell ebuilds we don't want everything
export PKGBUMPING=${version}
if [[ ${manifest} ]]; then
	GENTOO_MIRRORS= ebuild "${to}" manifest
	if [[ -f Manifest ]]; then
		git add Manifest
	fi
fi
git add "${to}"
echo "${version}" > .pkgbump-pv

if [[ ${diff} ]]; then
	"${scriptdir}"/pkgdiff-mg "${from}" "${to}"
fi
if [[ ${edit} ]]; then
	${EDITOR:-vim} "${to}"
fi
if [[ ${commit} ]]; then
	"${scriptdir}"/pkgcommit . -sS --bump
fi
