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

# Copyright (C) 2012-2015 Luke Shumaker <lukeshu@sbcglobal.net>
#
# License: GNU GPLv2+
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

LIBREUSER="${SUDO_USER:-$USER}"
if [[ $LIBREUSER == $USER ]]; then
	LIBREHOME=$HOME
else
	eval "LIBREHOME=~$LIBREUSER"
fi
if [[ -z ${XDG_CONFIG_HOME:-} ]]; then
	export XDG_CONFIG_HOME="${LIBREHOME}/.config"
fi
if [[ -z ${XDG_CACHE_HOME:-} ]]; then
	export XDG_CACHE_HOME="${LIBREHOME}/.cache"
fi

# Low-level generic functions ##################################################

# Usage: list_files $slug
# Lists the configuration files to be considered for $slug.
# Later files should take precedence over earlier files.
list_files() {
	local slug=$1
	local sysconfdir=${_librelib_conf_sh_sysconfdir:-@sysconfdir@}
	local pkgconfdir=${_librelib_conf_sh_pkgconfdir:-@pkgconfdir@}
	case $slug in
		abs)
			echo "${sysconfdir}/$slug.conf"
			echo "$LIBREHOME/.$slug.conf"
			;;
		makepkg)
			local manual="${MAKEPKG_CONF:-}"
			local system="${sysconfdir}/$slug.conf"
			local olduser="$LIBREHOME/.$slug.conf"
			local newuser="$XDG_CONFIG_HOME/pacman/$slug.conf"
			if [[ "$manual" != "$system" && -r "$manual" ]]; then
				# Manually-specified file
				echo "$manual"
			else
				# Normal file lookup
				echo "$system"
				if [[ -r "$olduser" && ! -r "$newuser" ]]; then
					echo "$olduser"
				else
					echo "$newuser"
				fi
			fi
			;;
		xbs*)
			echo "${sysconfdir}/xbs/$slug.conf"
			echo "$XDG_CONFIG_HOME/xbs/$slug.conf"
			;;
		libretools)
			echo "${sysconfdir}/$slug.conf"
			echo "$XDG_CONFIG_HOME/libretools/$slug.conf"
			;;
		*)
			echo "${pkgconfdir}/$slug.conf"
			echo "$XDG_CONFIG_HOME/libretools/$slug.conf"
			;;
	esac
}

# Usage: list_envvars $slug
# Lists the environmental variables that take precedence over the configuration
# files for $slug.
list_envvars() {
	local slug=$1
	case $slug in
		makepkg)
			printf '%s\n' \
				PKGDEST SRCDEST SRCPKGDEST LOGDEST \
				BUILDDIR \
				PKGEXT SRCEXT \
				GPGKEY PACKAGER \
				CARCH
			;;
		libretools)
			printf '%s\n' DIFFPROG
			;;
		xbs)
			printf '%s\n' BUILDSYSTEM
			;;
		*) :;;
	esac
}

# High-level generic functions #################################################

# Usage: load_files $slug
# Loads the configuration files for $slug in the proper order.
load_files() {
	local slug=$1
	local var
	local file

	# Save the existing versions at _VARNAME
	for var in $(list_envvars $slug); do
		[[ -n ${!var:-} ]] && eval "_$var=\${$var}"
	done

	# Load the files
	for file in $(list_files $slug); do
		if [[ -r $file ]]; then
			. "$file" || return 1
		fi
	done

	# Restore the _SAVED versions
	for var in $(list_envvars $slug); do
		eval "$var=\${_$var:-\${$var:-}}"
	done
}

# Usage: check_vars $slug VAR1 VAR2...
# Check whether the variables listed are properly set.
# If not, it prints a message saying to set them in the configuration file(s)
# for $slug.
check_vars() (
	local slug=$1; shift

	local ret=0

	local VAR
	for VAR in "$@"; do
		if [[ -z ${!VAR:-} ]]; then
			type print &>/dev/null || . libremessages
			if [[ $(list_files $slug|wc -l) -gt 1 ]]; then
				_l print "Configure '%s' in one of:" "$VAR"
				list_files $slug | sed 's/./  -> &/'
			else
				_l print "Configure '%s' in '%s'" "$VAR" "$(list_files $slug)"
			fi
			ret=1
		fi
	done >&2

	if [[ $ret != 0 ]]; then
		return 1
	fi
)

# Usage: get_var <slug> <var_name> <default_value>
# Does not work with arrays
get_var() (
	set +euE
	local slug=$1
	local setting=$2
	local default=$3
	load_files "$slug"
	printf '%s' "${!setting:-${default}}"
)

# Usage: set_var <slug> <var_name> <value>
# Does not work with arrays
set_var() {
	local slug=$1
	local key=$2
	local val=$3
	local file
	for file in $(list_files "$slug"|tac); do
		if [[ -w $file ]]; then
			sed -i "/^\s*$key=/d" "$file"
			printf '%s=%q\n' "$key" "$val" >> "$file"
			return 0
		fi
	done
	return 1
}

# PKGBUILD (not configuration, per se) #########################################

unset_PKGBUILD() {
	# This routine is based primarily off of the PKGBUILD(5) man-page,
	# version 4.2.0, dated 2014-12-31

	# This is kinda weird, but everything is more readable with
	# this as a utility function, but I didn't want to introduce a
	# new global function, so I just introduced it with the name
	# of a function that we get to unset anyway.  So it can't
	# clash with anything!
	mksource() {
		# For each arg, `unset -v` all variables matching ${arg} and ${arg}_*
		local v
		for v in "$@"; do
			unset -v "$v" $(declare -p|sed -rn "s/^declare -\S+ (${v}_[a-zA-Z0-9_]*)=.*/\1/p")
		done
	}

	# This line is taken from the makepkg source
	local known_hash_algos=('md5' 'sha1' 'sha224' 'sha256' 'sha384' 'sha512')

	# From the "OPTIONS AND DIRECTIVES" section (in order of mention)
	unset -v pkgname pkgver
	unset -f pkgver
	unset -v pkgrel pkgdesc epoch url license install changelog

	mksource source
	unset -v validpgpkeys noextract
	local sums=("${known_hash_algos[@]/%/sums}")
	mksource "${sums[@]}"

	unset -v groups arch backup
	mksource depends makedepends checkdepends optdepends
	mksource conflicts provides replaces
	unset -v options

	# From the "PACKAGING FUNCTIONS" section (in order of mention)
	unset -f package prepare build check

	# From the "PACKAGE SPLITTING" section
	unset -f $(declare -f|sed -n 's/^\(package_\S*\) ()\s*$/\1/p')
	unset -v pkgbase

	# These are used by the `librefetch` program
	unset -v mksource mknoextract "${sums[@]/#/mk}"
	unset -v mkdepends
	unset -f mksource
}

load_PKGBUILD() {
	local file=${1:-./PKGBUILD}
	unset_PKGBUILD
	CARCH="$(get_var makepkg CARCH "`uname -m`")"
	. "$file"
}