#!/usr/bin/env bash
# LibreStage
# Prepares packages for upload

# Copyright (C) 2010-2012 Nicolás Reynolds <fauno@parabola.nu>
# Copyright (C) 2011 Joshua Ismael Haase Hernández (xihh) <hahj87@gmail.com>
# Copyright (C) 2013-2014, 2017-2018, 2024 Luke T. Shumaker <lukeshu@parabola.nu>
# Copyright (C) 2020 Andreas Grapentin <andreas@grapentin.org>
#
# License: GNU GPLv3+
#
# This file is part of Parabola.
#
# Parabola 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 3 of the License, or
# (at your option) any later version.
#
# Parabola 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 Parabola. If not, see <http://www.gnu.org/licenses/>.

. "$(librelib messages)"
. "$(librelib conf)"

SUPPORTED_ARCHES=(armv7h i686 x86_64) # TODO: there is a WIP to define these in conf.sh

LimitArch="*"

usage() {
	print "Usage: %s [OPTIONS] [REPO]" "${0##*/}"
	print "Stages the package(s) build by ./PKGBUILD for upload."
	echo
	prose "The package(s) are staged for the named repository, or the name
	       of the parent directory if a repository is not named."
	echo
	print 'Options:'
	flag \
		'-A <ARCH>' 'Stage only packages built for arches matching the given wildcard string. Default: *' \
		'-h, --help' 'Show this message'
}

main() {
	# Parse options, set up
	local args mode=run repo
	if ! args="$(getopt -n "${0##*/}" -o 'hA:' -l 'help' -- "$@")"; then
		mode=errusage
	else
		eval "set -- $args"
		local flag
		while true; do
			flag=$1
			shift
			case "$flag" in
				-h | --help) [[ $mode == errusage ]] || mode=usage ;;
				A)
					LimitArch="$1"
					shift
					if ! in_array "$LimitArch" '*' "${SUPPORTED_ARCHES[@]}"; then
						gnuerror "the specified arch is not supported: %q" "$LimitArch"
						mode=errusage
					fi
					;;
				--) break ;;
				*) panic 'unhandled flag: %q' "$flag" ;;
			esac
		done
		if [[ $mode == run ]]; then
			case $# in
				0) repo="$(basename "$(dirname "$PWD")")" ;;
				1) repo=$1 ;;
				*)
					gnuerror 'takes 0 or 1 arguments, got %d' "$#"
					mode=errusage
					;;
			esac
		fi
	fi
	case "$mode" in
		errusage)
			print "Try '%s --help' for more information." "${0##*/}" >&2
			return $EXIT_INVALIDARGUMENT
			;;
		usage)
			usage
			return $EXIT_SUCCESS
			;;
		run) : ;;
		*) panic 'invalid mode: %q' "$mode" ;;
	esac

	if [[ -w / ]]; then
		error "This program should be run as a regular user"
		return $EXIT_NOPERMISSION
	fi

	if ! [[ -e ./PKGBUILD ]]; then
		error "PKGBUILD not found"
		return $EXIT_FAILURE
	fi

	# Load configuration
	declare -i ret=0
	load_conf libretools.conf WORKDIR || ret=$?
	load_conf makepkg.conf || ret=$?    # for PKGDEST, SRCDEST, and SRCPKGDEST, which are optional
	load_conf librefetch.conf || ret=$? # for MIRRORS, which is optional
	[[ $ret == 0 ]] || exit $ret

	SRCPKGPOOL="$WORKDIR/staging/sources/parabola"

	# Load the PKGBUILD
	if [[ $LimitArch == '*' ]]; then
		load_PKGBUILD
	else
		CARCH=$LimitArch load_PKGBUILD
	fi

	# Now for the main routine.
	local staged=false
	slock 8 "${WORKDIR}/staging.lock" \
		'Waiting for a shared lock on the staging directory'

	# Look for (libre)makepkg output
	local CARCH _pkgname pkgnames pkgfile
	for CARCH in "${arch[@]}"; do
		# Skip this arch if necessary
		[[ $CARCH == $LimitArch ]] || continue

		# This supports both pacman < 5.1 pkgname-debug
		# packages and pacman >= 5.1 pkgbase-debug packages.
		pkgnames=("${pkgname[@]}" "${pkgname[@]/%/-debug}")
		in_array "$pkgbase" "${pkgname[@]}" || pkgnames+=("${pkgbase}-debug")
		for _pkgname in "${pkgnames[@]}"; do
			if ! pkgfile=$(find_cached_package "$_pkgname" "$(get_full_version "$_pkgname")" "$CARCH"); then
				continue
			fi

			msg 'Found package: %s' "${pkgfile##*/}"

			# This little check is from devtools:commitpkg
			if grep -q "packager = Unknown Packager" <(bsdtar -xOqf "$pkgfile" .PKGINFO); then
				die "PACKAGER was not set when building package"
			fi

			mkdir -p "${WORKDIR}/staging/${repo}"
			if cp "$pkgfile" "${WORKDIR}/staging/${repo}/${pkgfile##*/}"; then
				msg2 "%s staged on [%s]" "$_pkgname" "$repo"
				staged=true
			else
				error "Can't put %s on [%s]" "$_pkgname" "$repo"
				return $EXIT_FAILURE
			fi
		done
		if pkgfile=$(find_cached_srcpackage "$pkgbase" "$(get_full_version)" "$CARCH"); then
			msg 'Found source package: %s' "${pkgfile##*/}"

			mkdir -p "$SRCPKGPOOL"
			if cp "$pkgfile" "$SRCPKGPOOL/${pkgfile##*/}"; then
				msg2 "%s staged on [%s]" "$pkgbase" sources
				staged=true
			else
				error "Can't put %s on [%s]" "$pkgbase" sources
				return $EXIT_FAILURE
			fi
		fi
	done

	# Look for librefetch output
	local netfile mirror path
	local srcurl srcname srcpath
	for netfile in "${source[@]}"; do
		for mirror in "${MIRRORS[@]}"; do
			srcurl=${netfile#*::}
			if [[ $srcurl == "$mirror"* ]]; then
				if [[ $netfile == *::* ]]; then
					srcname=${netfile%%::*}
				else
					srcname=${netfile##*/}
				fi

				srcpath=''
				for path in "./$srcname" "${SRCDEST:-.}/$srcname"; do
					if [[ -f $path ]]; then
						srcpath="$path"
						break
					fi
				done
				if [[ -n $srcpath ]]; then
					msg "Found generated source file: %s" "$srcname"
					local dest="${WORKDIR}/staging/other/${srcurl##"$mirror"}"
					mkdir -p -- "${dest%/*}"
					if cp "$srcpath" "$dest"; then
						msg2 "%s staged on [%s]" "$srcname" other
						staged=true
					else
						error "Can't put %s on [%s]" "$srcname" other
						return $EXIT_FAILURE
					fi
				fi
				break
			fi
		done
	done

	if $staged; then
		return $EXIT_SUCCESS
	else
		error "Nothing was staged"
		return $EXIT_FAILURE
	fi
}

main "$@"
