#!@BASH_SHELL@ -e
#
#   makepkg - make packages compatible for use with pacman
#   @configure_input@
#
#   Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
#   Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
#   Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
#   Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
#   Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
#   Copyright (c) 2006 by Alex Smith <alex@alex-smith.me.uk>
#   Copyright (c) 2006 by Andras Voroskoi <voroskoi@frugalware.org>
#
#   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/>.
#

# makepkg uses quite a few external programs during its execution. You
# need to have at least the following installed for makepkg to function:
#   awk, bsdtar (libarchive), bzip2, coreutils, fakeroot, file, find (findutils),
#   gettext, grep, gzip, openssl, sed, tput (ncurses), xz

# gettext initialization
export TEXTDOMAIN='pacman'
export TEXTDOMAINDIR='@localedir@'

# file -i does not work on Mac OSX unless legacy mode is set
export COMMAND_MODE='legacy'

myver='@PACKAGE_VERSION@'
confdir='@sysconfdir@'
BUILDSCRIPT='@BUILDSCRIPT@'
startdir="$PWD"
srcdir="$startdir/src"
pkgdir="$startdir/pkg"

packaging_options=('strip' 'docs' 'libtool' 'emptydirs' 'zipman' 'purge')
other_options=('ccache' 'distcc' 'buildflags' 'makeflags')
splitpkg_overrides=('pkgver' 'pkgrel' 'pkgdesc' 'arch' 'license' 'groups' \
                    'depends' 'optdepends' 'provides' 'conflicts' 'replaces' \
                    'backup' 'options' 'install' 'changelog')
readonly -a packaging_options other_options splitpkg_overrides

# Options
ASROOT=0
CLEANUP=0
CLEANCACHE=0
DEP_BIN=0
FORCE=0
INFAKEROOT=0
GENINTEG=0
SKIPINTEG=0
INSTALL=0
NOBUILD=0
NODEPS=0
NOEXTRACT=0
RMDEPS=0
REPKG=0
LOGGING=0
SOURCEONLY=0
IGNOREARCH=0
HOLDVER=0
BUILDFUNC=0
CHECKFUNC=0
PKGFUNC=0
SPLITPKG=0
PKGLIST=()

# Forces the pkgver of the current PKGBUILD. Used by the fakeroot call
# when dealing with svn/cvs/etc PKGBUILDs.
FORCE_VER=""

PACMAN_OPTS=

### SUBROUTINES ###

plain() {
	local mesg=$1; shift
	printf "${BOLD}    ${mesg}${ALL_OFF}\n" "$@" >&2
}

msg() {
	local mesg=$1; shift
	printf "${GREEN}==>${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
}

msg2() {
	local mesg=$1; shift
	printf "${BLUE}  ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
}

warning() {
	local mesg=$1; shift
	printf "${YELLOW}==> $(gettext "WARNING:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
}

error() {
	local mesg=$1; shift
	printf "${RED}==> $(gettext "ERROR:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
}


##
# Special exit call for traps, Don't print any error messages when inside,
# the fakeroot call, the error message will be printed by the main call.
##
trap_exit() {
	if (( ! INFAKEROOT )); then
		echo
		error "$@"
	fi
	[[ -n $srclinks ]] && rm -rf "$srclinks"
	exit 1
}


##
# Clean up function. Called automatically when the script exits.
##
clean_up() {
	local EXIT_CODE=$?

	if (( INFAKEROOT )); then
		# Don't clean up when leaving fakeroot, we're not done yet.
		return
	fi

	if (( ! EXIT_CODE && CLEANUP )); then
		local pkg file

		# If it's a clean exit and -c/--clean has been passed...
		msg "$(gettext "Cleaning up...")"
		rm -rf "$pkgdir" "$srcdir"
		if [[ -n $pkgbase ]]; then
			# TODO: this wasn't properly fixed in commit 2020e629
			local fullver=$(get_full_version $epoch $pkgver $pkgrel)
			# Can't do this unless the BUILDSCRIPT has been sourced.
			if (( BUILDFUNC )); then
				rm -f "${pkgbase}-${fullver}-${CARCH}-build.log"*
			fi
			if (( CHECKFUNC )); then
				rm -f "${pkgbase}-${fullver}-${CARCH}-check.log"*
			fi
			if (( PKGFUNC )); then
				rm -f "${pkgbase}-${fullver}-${CARCH}-package.log"*
			elif (( SPLITPKG )); then
				for pkg in ${pkgname[@]}; do
					rm -f "${pkgbase}-${fullver}-${CARCH}-package_${pkg}.log"*
				done
			fi

			# clean up dangling symlinks to packages
			for pkg in ${pkgname[@]}; do
				for file in ${pkg}-*-*-${CARCH}{${PKGEXT},${SRCEXT}}; do
					if [[ -h $file && ! -e $file ]]; then
						rm -f $file
					fi
				done
			done
		fi
	fi

	remove_deps
}


##
# Signal Traps
##
set -E
trap 'clean_up' 0
trap 'trap_exit "$(gettext "TERM signal caught. Exiting...")"' TERM HUP QUIT
trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT
trap 'trap_exit "$(gettext "An unknown error has occurred. Exiting...")"' ERR

# a source entry can have two forms :
# 1) "filename::http://path/to/file"
# 2) "http://path/to/file"

# Return the absolute filename of a source entry
#
# This function accepts a source entry or the already extracted filename of a
# source entry as input
get_filepath() {
	local file="$(get_filename "$1")"

	if [[ -f "$startdir/$file" ]]; then
		file="$startdir/$file"
	elif [[ -f "$SRCDEST/$file" ]]; then
		file="$SRCDEST/$file"
	else
		return 1
	fi

	echo "$file"
}

# Print 'source not found' error message and exit makepkg
missing_source_file() {
	error "$(gettext "Unable to find source file %s.")" "$(get_filename "$1")"
	plain "$(gettext "Aborting...")"
	exit 1 # $E_MISSING_FILE
}

# extract the filename from a source entry
get_filename() {
	# if a filename is specified, use it
	local filename="${1%%::*}"
	# if it is just an URL, we only keep the last component
	echo "${filename##*/}"
}

# extract the URL from a source entry
get_url() {
	# strip an eventual filename
	echo "${1#*::}"
}

##
#  usage : get_full_version( $epoch, $pkgver, $pkgrel )
# return : full version spec, including epoch (if necessary), pkgver, pkgrel
##
get_full_version() {
	if [[ $1 -eq 0 ]]; then
		# zero epoch case, don't include it in version
		echo $2-$3
	else
		echo $1:$2-$3
	fi
}

##
# Checks to see if options are present in makepkg.conf or PKGBUILD;
# PKGBUILD options always take precedence.
#
#  usage : check_option( $option )
# return : y - enabled
#          n - disabled
#          ? - not found
##
check_option() {
	local ret=$(in_opt_array "$1" ${options[@]})
	if [[ $ret != '?' ]]; then
		echo $ret
		return
	fi

	# fall back to makepkg.conf options
	ret=$(in_opt_array "$1" ${OPTIONS[@]})
	if [[ $ret != '?' ]]; then
		echo $ret
		return
	fi

	echo '?' # Not Found
}


##
# Check if option is present in BUILDENV
#
#  usage : check_buildenv( $option )
# return : y - enabled
#          n - disabled
#          ? - not found
##
check_buildenv() {
	echo $(in_opt_array "$1" ${BUILDENV[@]})
}


##
#  usage : in_opt_array( $needle, $haystack )
# return : y - enabled
#          n - disabled
#          ? - not found
##
in_opt_array() {
	local needle=$(tr '[:upper:]' '[:lower:]' <<< $1); shift

	local opt
	for opt in "$@"; do
		opt=$(tr '[:upper:]' '[:lower:]' <<< $opt)
		if [[ $opt = $needle ]]; then
			echo 'y' # Enabled
			return
		elif [[ $opt = "!$needle" ]]; then
			echo 'n' # Disabled
			return
		fi
	done

	echo '?' # Not Found
}


##
#  usage : in_array( $needle, $haystack )
# return : 0 - found
#          1 - not found
##
in_array() {
	local needle=$1; shift
	[[ -z $1 ]] && return 1 # Not Found
	local item
	for item in "$@"; do
		[[ $item = $needle ]] && return 0 # Found
	done
	return 1 # Not Found
}

get_downloadclient() {
	# $1 = URL with valid protocol prefix
	local url=$1
	local proto="${url%%://*}"

	# loop through DOWNLOAD_AGENTS variable looking for protocol
	local i
	for i in "${DLAGENTS[@]}"; do
		local handler="${i%%::*}"
		if [[ $proto = $handler ]]; then
			local agent="${i##*::}"
			break
		fi
	done

	# if we didn't find an agent, return an error
	if [[ -z $agent ]]; then
		error "$(gettext "There is no agent set up to handle %s URLs. Check %s.")" "$proto" "$MAKEPKG_CONF"
		plain "$(gettext "Aborting...")"
		exit 1 # $E_CONFIG_ERROR
	fi

	# ensure specified program is installed
	local program="${agent%% *}"
	if [[ ! -x $program ]]; then
		local baseprog="${program##*/}"
		error "$(gettext "The download program %s is not installed.")" "$baseprog"
		plain "$(gettext "Aborting...")"
		exit 1 # $E_MISSING_PROGRAM
	fi

	echo "$agent"
}

download_file() {
	# download command
	local dlcmd=$1
	# URL of the file
	local url=$2
	# destination file
	local file=$3
	# temporary download file, default to last component of the URL
	local dlfile="${url##*/}"

	# replace %o by the temporary dlfile if it exists
	if [[ $dlcmd = *%o* ]]; then
		dlcmd=${dlcmd//\%o/\"$file.part\"}
		dlfile="$file.part"
	fi
	# add the URL, either in place of %u or at the end
	if [[ $dlcmd = *%u* ]]; then
		dlcmd=${dlcmd//\%u/\"$url\"}
	else
		dlcmd="$dlcmd \"$url\""
	fi

	local ret=0
	eval "$dlcmd || ret=\$?"
	if (( ret )); then
		[[ ! -s $dlfile ]] && rm -f -- "$dlfile"
		return $ret
	fi

	# rename the temporary download file to the final destination
	if [[ $dlfile != $file ]]; then
		mv -f "$SRCDEST/$dlfile" "$SRCDEST/$file"
	fi
}

run_pacman() {
	local cmd
	printf -v cmd "%q " "$PACMAN" $PACMAN_OPTS "$@"
	if (( ! ASROOT )) && [[ ! $1 =~ ^-(T|Qq)$ ]]; then
		if [ "$(type -p sudo)" ]; then
			cmd="sudo $cmd"
		else
			cmd="su -c '$cmd'"
		fi
	fi
	eval "$cmd"
}

check_deps() {
	(( $# > 0 )) || return 0

	# Disable error trap in pacman subshell call as this breaks bash-3.2 compatibility
	# Also, a non-zero return value is not unexpected and we are manually dealing them
	set +E
	local ret=0
	local pmout
	pmout=$(run_pacman -T "$@") || ret=$?
	set -E 
	
	if (( ret == 127 )); then #unresolved deps
		echo "$pmout"
	elif (( ret )); then
		error "$(gettext "'%s' returned a fatal error (%i): %s")" "$PACMAN" "$ret" "$pmout"
		return "$ret"
	fi
}

handle_deps() {
	local R_DEPS_SATISFIED=0
	local R_DEPS_MISSING=1

	(( $# == 0 )) && return $R_DEPS_SATISFIED

	local deplist="$*"

	if (( ! DEP_BIN )); then
		return $R_DEPS_MISSING
	fi

	if (( DEP_BIN )); then
		# install missing deps from binary packages (using pacman -S)
		msg "$(gettext "Installing missing dependencies...")"

		if ! run_pacman -S --asdeps $deplist; then
			error "$(gettext "'%s' failed to install missing dependencies.")" "$PACMAN"
			exit 1 # TODO: error code
		fi
	fi

	# we might need the new system environment
	# avoid triggering the ERR trap
	local restoretrap=$(trap -p ERR)
	trap - ERR
	source /etc/profile &>/dev/null
	eval $restoretrap

	return $R_DEPS_SATISFIED
}

resolve_deps() {
	local R_DEPS_SATISFIED=0
	local R_DEPS_MISSING=1

	# deplist cannot be declared like this: local deplist=$(foo)
	# Otherwise, the return value will depend on the assignment.
	local deplist
	deplist="$(set +E; check_deps $*)" || exit 1
	[[ -z $deplist ]] && return $R_DEPS_SATISFIED

	if handle_deps $deplist; then
		# check deps again to make sure they were resolved
		deplist="$(set +E; check_deps $*)" || exit 1
		[[ -z $deplist ]] && return $R_DEPS_SATISFIED
	fi

	msg "$(gettext "Missing Dependencies:")"
	local dep
	for dep in $deplist; do
		msg2 "$dep"
	done

	return $R_DEPS_MISSING
}

remove_deps() {
	(( ! RMDEPS )) && return

	# check for packages removed during dependency install (e.g. due to conflicts)
	# removing all installed packages is risky in this case
	if [[ -n  $(comm -23 <(printf "%s\n" "${original_pkglist[@]}") \
			<(printf "%s\n" "${current_pkglist[@]}")) ]]; then
	  warning "$(gettext "Failed to remove installed dependencies.")"
	  return 0
	fi

	local deplist=($(comm -13  <(printf "%s\n" "${original_pkglist[@]}") \
			<(printf "%s\n" "${current_pkglist[@]}")))
	(( ${#deplist[@]} == 0 )) && return

	msg "Removing installed dependencies..."
	# exit cleanly on failure to remove deps as package has been built successfully
	if ! run_pacman -Rn ${deplist[@]}; then
		warning "$(gettext "Failed to remove installed dependencies.")"
		return 0
	fi
}

download_sources() {
	msg "$(gettext "Retrieving Sources...")"

	pushd "$SRCDEST" &>/dev/null

	local netfile
	for netfile in "${source[@]}"; do
		local file=$(get_filepath "$netfile" || true)
		if [[ -n "$file" ]]; then
			msg2 "$(gettext "Found %s")" "${file##*/}"
			ln -sf "$file" "$srcdir/"
			continue
		fi

		file=$(get_filename "$netfile")
		local url=$(get_url "$netfile")

		# if we get here, check to make sure it was a URL, else fail
		if [[ $file = $url ]]; then
			error "$(gettext "%s was not found in the build directory and is not a URL.")" "$file"
			exit 1 # $E_MISSING_FILE
		fi

		# find the client we should use for this URL
		local dlclient=$(get_downloadclient "$url") || exit $?

		msg2 "$(gettext "Downloading %s...")" "$file"
		# fix flyspray bug #3289
		local ret=0
		download_file "$dlclient" "$url" "$file" || ret=$?
		if (( ret )); then
			error "$(gettext "Failure while downloading %s")" "$file"
			plain "$(gettext "Aborting...")"
			exit 1
		fi
		rm -f "$srcdir/$file"
		ln -s "$SRCDEST/$file" "$srcdir/"
	done

	popd &>/dev/null
}

get_integlist() {
	local integ
	local integlist=()

	for integ in md5 sha1 sha256 sha384 sha512; do
		local integrity_sums=($(eval echo "\${${integ}sums[@]}"))
		if [[ -n "$integrity_sums" ]]; then
			integlist=(${integlist[@]} $integ)
		fi
	done

	if (( ${#integlist[@]} > 0 )); then
		echo ${integlist[@]}
	else
		echo ${INTEGRITY_CHECK[@]}
	fi
}

generate_checksums() {
	msg "$(gettext "Generating checksums for source files...")"
	plain ""

	if ! type -p openssl >/dev/null; then
		error "$(gettext "Cannot find openssl.")"
		exit 1 # $E_MISSING_PROGRAM
	fi

	local integlist
	if (( $# == 0 )); then
		integlist=$(get_integlist)
	else
		integlist=$@
	fi

	local integ
	for integ in ${integlist[@]}; do
		integ=$(tr '[:upper:]' '[:lower:]' <<< "$integ")
		case "$integ" in
			md5|sha1|sha256|sha384|sha512) : ;;
			*)
				error "$(gettext "Invalid integrity algorithm '%s' specified.")" "$integ"
				exit 1;; # $E_CONFIG_ERROR
		esac

		local ct=0
		local numsrc=${#source[@]}
		echo -n "${integ}sums=("

		local i
		local indent=''
		for (( i = 0; i < ${#integ} + 6; i++ )); do
			indent="$indent "
		done

		local netfile
		for netfile in "${source[@]}"; do
			local file="$(get_filepath "$netfile")" || missing_source_file "$netfile"
			local sum="$(openssl dgst -${integ} "$file")"
			sum=${sum##* }
			(( ct )) && echo -n "$indent"
			echo -n "'$sum'"
			ct=$(($ct+1))
			(( $ct < $numsrc )) && echo
		done

		echo ")"
	done
}

check_checksums() {
	(( ! ${#source[@]} )) && return 0

	if ! type -p openssl >/dev/null; then
		error "$(gettext "Cannot find openssl.")"
		exit 1 # $E_MISSING_PROGRAM
	fi

	local correlation=0
	local integ required
	for integ in md5 sha1 sha256 sha384 sha512; do
		local integrity_sums=($(eval echo "\${${integ}sums[@]}"))
		if (( ${#integrity_sums[@]} == ${#source[@]} )); then
			msg "$(gettext "Validating source files with %s...")" "${integ}sums"
			correlation=1
			local errors=0
			local idx=0
			local file
			for file in "${source[@]}"; do
				local found=1
				file="$(get_filename "$file")"
				echo -n "    $file ... " >&2

				if ! file="$(get_filepath "$file")"; then
					echo "$(gettext "NOT FOUND")" >&2
					errors=1
					found=0
				fi

				if (( $found )) ; then
					local expectedsum=$(tr '[:upper:]' '[:lower:]' <<< "${integrity_sums[$idx]}")
					local realsum="$(openssl dgst -${integ} "$file")"
					realsum="${realsum##* }"
					if [[ $expectedsum = $realsum ]]; then
						echo "$(gettext "Passed")" >&2
					else
						echo "$(gettext "FAILED")" >&2
						errors=1
					fi
				fi

				idx=$((idx + 1))
			done

			if (( errors )); then
				error "$(gettext "One or more files did not pass the validity check!")"
				exit 1 # TODO: error code
			fi
		elif (( ${#integrity_sums[@]} )); then
			error "$(gettext "Integrity checks (%s) differ in size from the source array.")" "$integ"
			exit 1 # TODO: error code
		fi
	done

	if (( ! correlation )); then
		error "$(gettext "Integrity checks are missing.")"
		exit 1 # TODO: error code
	fi
}

extract_sources() {
	msg "$(gettext "Extracting Sources...")"
	local netfile
	for netfile in "${source[@]}"; do
		local file=$(get_filename "$netfile")
		if in_array "$file" ${noextract[@]}; then
			#skip source files in the noextract=() array
			#  these are marked explicitly to NOT be extracted
			continue
		fi


		# fix flyspray #6246
		local file_type=$(file -bizL "$file")
		local ext=${file##*.}
		local cmd=''
		case "$file_type" in
			*application/x-tar*|*application/zip*|*application/x-zip*|*application/x-cpio*)
				cmd="bsdtar" ;;
			*application/x-gzip*)
				case "$ext" in
					gz|z|Z) cmd="gzip" ;;
					*) continue;;
				esac ;;
			*application/x-bzip*)
				case "$ext" in
					bz2|bz) cmd="bzip2" ;;
					*) continue;;
				esac ;;
			*application/x-xz*)
				case "$ext" in
					xz) cmd="xz" ;;
					*) continue;;
				esac ;;
			*)
				# See if bsdtar can recognize the file
				if bsdtar -tf "$file" -q '*' &>/dev/null; then
					cmd="bsdtar"
				else
					continue
				fi ;;
		esac

		local ret=0
		msg2 "$(gettext "Extracting %s with %s")" "$file" "$cmd"
		if [[ $cmd = bsdtar ]]; then
			$cmd -xf "$file" || ret=$?
		else
			rm -f "${file%.*}"
			$cmd -dcf "$file" > "${file%.*}" || ret=$?
		fi
		if (( ret )); then
			error "$(gettext "Failed to extract %s")" "$file"
			plain "$(gettext "Aborting...")"
			exit 1
		fi
	done

	if (( EUID == 0 )); then
		# change perms of all source files to root user & root group
		chown -R 0:0 "$srcdir"
	fi
}

error_function() {
	if [[ -p $logpipe ]]; then
		rm "$logpipe"
	fi
	# first exit all subshells, then print the error
	if (( ! BASH_SUBSHELL )); then
		error "$(gettext "A failure occurred in %s().")" "$1"
		plain "$(gettext "Aborting...")"
		remove_deps
	fi
	exit 2 # $E_BUILD_FAILED
}

run_function() {
	if [[ -z $1 ]]; then
		return 1
	fi
	local pkgfunc="$1"

	# clear user-specified buildflags if requested
	if [[ $(check_option buildflags) = "n" ]]; then
		CFLAGS=""
		CXXFLAGS=""
		LDFLAGS=""
	fi

	# clear user-specified makeflags if requested
	if [[ $(check_option makeflags) = "n" ]]; then
		MAKEFLAGS=""
	fi

	msg "$(gettext "Starting %s()...")" "$pkgfunc"
	cd "$srcdir"

	# ensure all necessary build variables are exported
	export CFLAGS CXXFLAGS LDFLAGS MAKEFLAGS CHOST
	# save our shell options so pkgfunc() can't override what we need
	local shellopts=$(shopt -p)

	local ret=0
	local restoretrap
	if (( LOGGING )); then
		local fullver=$(get_full_version $epoch $pkgver $pkgrel)
		local BUILDLOG="${startdir}/${pkgbase}-${fullver}-${CARCH}-$pkgfunc.log"
		if [[ -f $BUILDLOG ]]; then
			local i=1
			while true; do
				if [[ -f $BUILDLOG.$i ]]; then
					i=$(($i +1))
				else
					break
				fi
			done
			mv "$BUILDLOG" "$BUILDLOG.$i"
		fi

		# ensure overridden package variables survive tee with split packages
		logpipe=$(mktemp -u "$startdir/logpipe.XXXXXXXX")
		mkfifo "$logpipe"
		exec 3>&1
		tee "$BUILDLOG" < "$logpipe" &
		exec 1>"$logpipe" 2>"$logpipe"
		restoretrap=$(trap -p ERR)
		trap 'error_function $pkgfunc' ERR
		$pkgfunc 2>&1
		eval $restoretrap
		sync
		exec 1>&3 2>&3 3>&-
		rm "$logpipe"
	else
		restoretrap=$(trap -p ERR)
		trap 'error_function $pkgfunc' ERR
		$pkgfunc 2>&1
		eval $restoretrap
	fi
	# reset our shell options
	eval "$shellopts"
}

run_build() {
	# use distcc if it is requested (check buildenv and PKGBUILD opts)
	if [[ $(check_buildenv distcc) = "y" && $(check_option distcc) != "n" ]]; then
		[[ -d /usr/lib/distcc/bin ]] && export PATH="/usr/lib/distcc/bin:$PATH"
		export DISTCC_HOSTS
	elif [[ $(check_option distcc) = "n" ]]; then
		# if it is not wanted, clear the makeflags too
		MAKEFLAGS=""
	fi

	# use ccache if it is requested (check buildenv and PKGBUILD opts)
	if [[ $(check_buildenv ccache) = "y" && $(check_option ccache) != "n" ]]; then
		[[ -d /usr/lib/ccache/bin ]] && export PATH="/usr/lib/ccache/bin:$PATH"
	fi

	run_function "build"
}

run_check() {
	run_function "check"
}

run_package() {
	local pkgfunc
	if [[ -z $1 ]]; then
		pkgfunc="package"
	else
		pkgfunc="package_$1"
	fi

	run_function "$pkgfunc"
}

tidy_install() {
	cd "$pkgdir"
	msg "$(gettext "Tidying install...")"

	if [[ $(check_option docs) = "n" && -n ${DOC_DIRS[*]} ]]; then
		msg2 "$(gettext "Removing doc files...")"
		rm -rf ${DOC_DIRS[@]}
	fi

	if [[ $(check_option purge) = "y" && -n ${PURGE_TARGETS[*]} ]]; then
		msg2 "$(gettext "Purging other files...")"
		local pt
		for pt in "${PURGE_TARGETS[@]}"; do
			if [[ ${pt} = ${pt//\/} ]]; then
				find . -type f -name "${pt}" -exec rm -f -- '{}' \;
			else
				rm -f ${pt}
			fi
		done
	fi

	if [[ $(check_option zipman) = "y" && -n ${MAN_DIRS[*]} ]]; then
		msg2 "$(gettext "Compressing man and info pages...")"
		local manpage ext file link hardlinks hl
		find ${MAN_DIRS[@]} -type f 2>/dev/null |
		while read manpage ; do
			ext="${manpage##*.}"
			file="${manpage##*/}"
			if [[ $ext != gz && $ext != bz2 ]]; then
				# update symlinks to this manpage
				find ${MAN_DIRS[@]} -lname "$file" 2>/dev/null |
				while read link ; do
					rm -f "$link"
					ln -sf "${file}.gz" "${link}.gz"
				done

				# check file still exists (potentially already compressed due to hardlink)
				if [[ -f ${manpage} ]]; then
					# find hard links and remove them
					#   the '|| true' part keeps the script from bailing if find returned an
					#   error, such as when one of the man directories doesn't exist
					hardlinks="$(find ${MAN_DIRS[@]} \! -name "$file" -samefile "$manpage" 2>/dev/null)" || true
					for hl in ${hardlinks}; do
						rm -f "${hl}";
					done
					# compress the original
					gzip -9 "$manpage"
					# recreate hard links removed earlier
					for hl in ${hardlinks}; do
						ln "${manpage}.gz" "${hl}.gz"
						chmod 644 ${hl}.gz
					done
				fi
			fi
		done
	fi

	if [[ $(check_option strip) = y ]]; then
		msg2 "$(gettext "Stripping unneeded symbols from binaries and libraries...")"
		# make sure library stripping variables are defined to prevent excess stripping
		[[ -z ${STRIP_SHARED+x} ]] && STRIP_SHARED="-S"
		[[ -z ${STRIP_STATIC+x} ]] && STRIP_STATIC="-S"
		local binary
		find . -type f -perm -u+w 2>/dev/null | while read binary ; do
			case "$(file -bi "$binary")" in
				*application/x-sharedlib*)  # Libraries (.so)
					/usr/bin/strip $STRIP_SHARED "$binary";;
				*application/x-archive*)    # Libraries (.a)
					/usr/bin/strip $STRIP_STATIC "$binary";;
				*application/x-executable*) # Binaries
					/usr/bin/strip $STRIP_BINARIES "$binary";;
			esac
		done
	fi

	if [[ $(check_option libtool) = "n" ]]; then
		msg2 "$(gettext "Removing libtool .la files...")"
		find . ! -type d -name "*.la" -exec rm -f -- '{}' \;
	fi

	if [[ $(check_option emptydirs) = "n" ]]; then
		msg2 "$(gettext "Removing empty directories...")"
		find . -depth -type d -empty -delete
	fi
}

write_pkginfo() {
	local builddate=$(date -u "+%s")
	if [[ -n $PACKAGER ]]; then
		local packager="$PACKAGER"
	else
		local packager="Unknown Packager"
	fi
	local size="$(@DUPATH@ -sk)"
	size="$(( ${size%%[^0-9]*} * 1024 ))"

	msg2 "$(gettext "Generating .PKGINFO file...")"
	echo "# Generated by makepkg $myver"
	if (( INFAKEROOT )); then
		echo "# using $(fakeroot -v)"
	fi
	echo "# $(LC_ALL=C date -u)"
	echo "pkgname = $1"
	(( SPLITPKG )) && echo pkgbase = $pkgbase
	echo "pkgver = $(get_full_version $epoch $pkgver $pkgrel)"
	echo "pkgdesc = $pkgdesc"
	echo "url = $url"
	echo "builddate = $builddate"
	echo "packager = $packager"
	echo "size = $size"
	echo "arch = $PKGARCH"

	[[ $license ]]    && printf "license = %s\n"   "${license[@]}"
	[[ $replaces ]]   && printf "replaces = %s\n"  "${replaces[@]}"
	[[ $groups ]]     && printf "group = %s\n"     "${groups[@]}"
	[[ $depends ]]    && printf "depend = %s\n"    "${depends[@]}"
	[[ $optdepends ]] && printf "optdepend = %s\n" "${optdepends[@]}"
	[[ $conflicts ]]  && printf "conflict = %s\n"  "${conflicts[@]}"
	[[ $provides ]]   && printf "provides = %s\n"  "${provides[@]}"
	[[ $backup ]]     && printf "backup = %s\n"    "${backup[@]}"

	local it
	for it in "${packaging_options[@]}"; do
		local ret="$(check_option $it)"
		if [[ $ret != "?" ]]; then
			if [[ $ret = y ]]; then
				echo "makepkgopt = $it"
			else
				echo "makepkgopt = !$it"
			fi
		fi
	done

	# TODO maybe remove this at some point
	# warn if license array is not present or empty
	if [[ -z $license ]]; then
		warning "$(gettext "Please add a license line to your %s!")" "$BUILDSCRIPT"
		plain "$(gettext "Example for GPL\'ed software: license=('GPL').")"
	fi
}

check_package() {
	cd "$pkgdir"

	# check existence of backup files
	local file
	for file in "${backup[@]}"; do
		if [[ ! -f $file ]]; then
			warning "$(gettext "Backup entry file not in package : %s")" "$file"
		fi
	done

	# check for references to the build and package directory
	if find "${pkgdir}" -type f -print0 | xargs -0  grep -q -I "${srcdir}" ; then
		warning "$(gettext "Package contains reference to %s")" "\$srcdir"
	fi
	if find "${pkgdir}" -type f -print0 | xargs -0  grep -q -I "${pkgdir}" ; then
		warning "$(gettext "Package contains reference to %s")" "\$pkgdir"
	fi

}

create_package() {
	if [[ ! -d $pkgdir ]]; then
		error "$(gettext "Missing pkg/ directory.")"
		plain "$(gettext "Aborting...")"
		exit 1 # $E_MISSING_PKGDIR
	fi

	check_package

	cd "$pkgdir"
	msg "$(gettext "Creating package...")"

	local nameofpkg
	if [[ -z $1 ]]; then
		nameofpkg="$pkgname"
	else
		nameofpkg="$1"
	fi

	if [[ $arch = "any" ]]; then
		PKGARCH="any"
	else
		PKGARCH=$CARCH
	fi

	write_pkginfo $nameofpkg > .PKGINFO

	local comp_files=".PKGINFO"

	# check for changelog/install files
	for i in 'changelog' 'install'; do
		orig=${!i}
		dest=$(tr '[:lower:]' '[:upper:]' <<<".$i")

		if [[ -n $orig ]]; then
			msg2 "$(gettext "Adding %s file...")" "$i"
			cp "$startdir/$orig" "$dest"
			chmod 644 "$dest"
			comp_files+=" $dest"
		fi
	done

	# tar it up
	msg2 "$(gettext "Compressing package...")"

	local EXT
	case "$PKGEXT" in
		*tar.gz)  EXT=${PKGEXT%.gz} ;;
		*tar.bz2) EXT=${PKGEXT%.bz2} ;;
		*tar.xz)  EXT=${PKGEXT%.xz} ;;
		*tar)     EXT=${PKGEXT} ;;
		*) warning "$(gettext "'%s' is not a valid archive extension.")" \
		"$PKGEXT" ; EXT=$PKGEXT ;;
	esac

	local fullver=$(get_full_version $epoch $pkgver $pkgrel)
	local pkg_file="$PKGDEST/${nameofpkg}-${fullver}-${PKGARCH}${PKGEXT}"
	local ret=0

	# when fileglobbing, we want * in an empty directory to expand to
	# the null string rather than itself
	shopt -s nullglob
	# TODO: Maybe this can be set globally for robustness
	shopt -s -o pipefail
	bsdtar -cf - $comp_files * |
	case "$PKGEXT" in
	    *tar.gz)  gzip -c -f -n ;;
	    *tar.bz2) bzip2 -c -f ;;
	    *tar.xz)  xz -c -z - ;;
	    *tar)     cat ;;
	esac > ${pkg_file} || ret=$?

	shopt -u nullglob
	shopt -u -o pipefail

	if (( ret )); then
		error "$(gettext "Failed to create package file.")"
		exit 1 # TODO: error code
	fi

	if (( ! ret )) && [[ ! "$PKGDEST" -ef "${startdir}" ]]; then
		ln -sf "${pkg_file}" "${pkg_file/$PKGDEST/$startdir}"
		ret=$?
	fi

	if (( ret )); then
		warning "$(gettext "Failed to create symlink to package file.")"
	fi
}

create_srcpackage() {
	cd "$startdir"

	# Get back to our src directory so we can begin with sources.
	mkdir -p "$srcdir"
	chmod a-s "$srcdir"
	cd "$srcdir"
	if (( ! SKIPINTEG || SOURCEONLY == 2 )); then
		download_sources
	fi
	if (( ! SKIPINTEG )); then
		# We can only check checksums if we have all files.
		check_checksums
	else
		warning "$(gettext "Skipping integrity checks.")"
	fi
	cd "$startdir"

	msg "$(gettext "Creating source package...")"
	local srclinks="$(mktemp -d "$startdir"/srclinks.XXXXXXXXX)"
	mkdir "${srclinks}"/${pkgbase}

	msg2 "$(gettext "Adding %s...")" "$BUILDSCRIPT"
	ln -s "${BUILDFILE}" "${srclinks}/${pkgbase}/${BUILDSCRIPT}"

	local file
	for file in "${source[@]}"; do
		if [[ -f $file ]]; then
			msg2 "$(gettext "Adding %s...")" "$file"
			ln -s "${startdir}/$file" "$srclinks/$pkgbase"
		elif (( SOURCEONLY == 2 )); then
			local absfile=$(get_filepath "$file") || missing_source_file "$file"
			msg2 "$(gettext "Adding %s...")" "${absfile##*/}"
			ln -s "$absfile" "$srclinks/$pkgbase"
		fi
	done

	local i
	for i in 'changelog' 'install'; do
		local filelist=$(sed -n "s/^[[:space:]]*$i=//p" "$BUILDSCRIPT")
		local file
		for file in $filelist; do
			# evaluate any bash variables used
			eval file=${file}
			if [[ ! -f "${srclinks}/${pkgbase}/$file" ]]; then
				msg2 "$(gettext "Adding %s file (%s)...")" "$i" "${file}"
				ln -s "${startdir}/$file" "${srclinks}/${pkgbase}/"
			fi
		done
	done

	local TAR_OPT
	case "$SRCEXT" in
		*tar.gz)  TAR_OPT="z" ;;
		*tar.bz2) TAR_OPT="j" ;;
		*tar.xz)  TAR_OPT="J" ;;
		*tar)     TAR_OPT=""  ;;
		*) warning "$(gettext "'%s' is not a valid archive extension.")" \
		"$SRCEXT" ;;
	esac

	local fullver=$(get_full_version $epoch $pkgver $pkgrel)
	local pkg_file="$SRCPKGDEST/${pkgbase}-${fullver}${SRCEXT}"

	# tar it up
	msg2 "$(gettext "Compressing source package...")"
	cd "${srclinks}"
	if ! bsdtar -c${TAR_OPT}Lf "$pkg_file" ${pkgbase}; then
		error "$(gettext "Failed to create source package file.")"
		exit 1 # TODO: error code
	fi

	if (( ! ret )) && [[ ! "$SRCPKGDEST" -ef "${startdir}" ]]; then
		ln -sf "${pkg_file}" "${pkg_file/$SRCPKGDEST/$startdir}"
		ret=$?
	fi

	if (( ret )); then
		warning "$(gettext "Failed to create symlink to source package file.")"
	fi

	cd "${startdir}"
	rm -rf "${srclinks}"
}

install_package() {
	(( ! INSTALL )) && return

	if (( ! SPLITPKG )); then
		msg "$(gettext "Installing package %s with %s -U...")" "$pkgname" "$PACMAN"
	else
		msg "$(gettext "Installing %s package group with %s -U...")" "$pkgbase" "$PACMAN"
	fi

	local fullver pkg pkglist
	for pkg in ${pkgname[@]}; do
		# TODO: this wasn't properly fixed in commit 2020e629
		fullver=$(get_full_version $epoch $pkgver $pkgrel)
		if [[ -f $PKGDEST/${pkg}-${fullver}-${CARCH}${PKGEXT} ]]; then
			pkglist+=" $PKGDEST/${pkg}-${fullver}-${CARCH}${PKGEXT}"
		else
			pkglist+=" $PKGDEST/${pkg}-${fullver}-any${PKGEXT}"
		fi
	done

	if ! run_pacman -U $pkglist; then
		warning "$(gettext "Failed to install built package(s).")"
		return 0
	fi
}

check_sanity() {
	# check for no-no's in the build script
	local i
	local ret=0
	for i in 'pkgname' 'pkgrel' 'pkgver'; do
		if [[ -z ${!i} ]]; then
			error "$(gettext "%s is not allowed to be empty.")" "$i"
			ret=1
		fi
	done

	for i in "${pkgname[@]}"; do
		if [[ ${i:0:1} = "-" ]]; then
			error "$(gettext "%s is not allowed to start with a hyphen.")" "pkgname"
			ret=1
		fi
	done

	if [[ ${pkgbase:0:1} = "-" ]]; then
		error "$(gettext "%s is not allowed to start with a hyphen.")" "pkgbase"
		ret=1
	fi
	if [[ $pkgver =~ [:-] ]]; then
		error "$(gettext "%s is not allowed to contain colons or hyphens.")" "pkgver"
		ret=1
	fi
	if [[ $pkgrel != ${pkgrel//-/} ]]; then
		error "$(gettext "%s is not allowed to contain hyphens.")" "pkgrel"
		ret=1
	fi

	if [[ ! $epoch =~ ^[0-9]*$ ]]; then
		error "$(gettext "%s must be an integer.")" "epoch"
		ret=1
	fi

	if [[ $arch != 'any' ]]; then
		if ! in_array $CARCH ${arch[@]}; then
			if (( ! IGNOREARCH )); then
				error "$(gettext "%s is not available for the '%s' architecture.")" "$pkgbase" "$CARCH"
				plain "$(gettext "Note that many packages may need a line added to their %s")" "$BUILDSCRIPT"
				plain "$(gettext "such as arch=('%s').")" "$CARCH"
				ret=1
			fi
		fi
	fi

	local provides_list=()
	eval $(awk '/^[[:space:]]*provides=/,/\)/' "$BUILDFILE" | sed "s/provides=/provides_list+=/")
	for i in ${provides_list[@]}; do
		if [[ $i != ${i//</} || $i != ${i//>/} ]]; then
			error "$(gettext "Provides array cannot contain comparison (< or >) operators.")"
			ret=1
		fi
	done

	local backup_list=()
	eval $(awk '/^[[:space:]]*backup=/,/\)/' "$BUILDFILE" | sed "s/backup=/backup_list+=/")
	for i in "${backup_list[@]}"; do
		if [[ ${i:0:1} = "/" ]]; then
			error "$(gettext "Backup entry should not contain leading slash : %s")" "$i"
			ret=1
		fi
	done

	local optdepends_list=()
	eval $(awk '/^[[:space:]]*optdepends=/,/\)/' "$BUILDFILE" | sed "s/optdepends=/optdepends_list+=/")
	for i in "${optdepends_list[@]}"; do
		local pkg=${i%%:*}
		if [[ ! $pkg =~ ^[[:alnum:]\>\<\=\.\+\_\-]+$ ]]; then
			error "$(gettext "Invalid syntax for optdepend : '%s'")" "$i"
			ret=1
		fi
	done

	for i in 'changelog' 'install'; do
		local filelist=$(sed -n "s/^[[:space:]]*$i=//p" "$BUILDFILE") 
		local file
		for file in $filelist; do
			# evaluate any bash variables used
			eval file=${file}
			if [[ ! -f $file ]]; then
				error "$(gettext "%s file (%s) does not exist.")" "$i" "$file"
				ret=1
			fi
		done
	done

	local valid_options=1
	local known kopt options_list
	eval $(awk '/^[[:space:]]*options=/,/\)/' "$BUILDFILE" | sed "s/options=/options_list+=/")
	for i in ${options_list[@]}; do
		known=0
		# check if option matches a known option or its inverse
		for kopt in ${packaging_options[@]} ${other_options[@]}; do
			if [[ ${i} = ${kopt} || ${i} = "!${kopt}" ]]; then
				known=1
			fi
		done
		if (( ! known )); then
			error "$(gettext "options array contains unknown option '%s'")" "$i"
			valid_options=0
		fi
	done
	if (( ! valid_options )); then
		ret=1
	fi

	if (( ${#pkgname[@]} > 1 )); then
		for i in ${pkgname[@]}; do
			if ! declare -f package_${i} >/dev/null; then
				error "$(gettext "missing package function for split package '%s'")" "$i"
				ret=1
			fi
		done
	fi

	for i in ${PKGLIST[@]}; do
		if ! in_array $i ${pkgname[@]}; then
			error "$(gettext "requested package %s is not provided in %s")" "$i" "$BUILDFILE"
			ret=1
		fi
	done

	return $ret
}

devel_check() {
	newpkgver=""

	# Do not update pkgver if --holdver is set, when building a source package, repackaging,
	# reading PKGBUILD from pipe (-f), or if we cannot write to the file (-w)
	if (( HOLDVER || SOURCEONLY || REPKG )) \
		            || [[ ! -f $BUILDFILE || ! -w $BUILDFILE ]]; then
		return
	fi

	if [[ -z $FORCE_VER ]]; then
		# Check if this is a svn/cvs/etc PKGBUILD; set $newpkgver if so.
		# This will only be used on the first call to makepkg; subsequent
		# calls to makepkg via fakeroot will explicitly pass the version
		# number to avoid having to determine the version number twice.
		# Also do a brief check to make sure we have the VCS tool available.
		oldpkgver=$pkgver
		if [[ -n ${_darcstrunk} && -n ${_darcsmod} ]] ; then
			type -p darcs >/dev/null || return 0
			msg "$(gettext "Determining latest %s revision...")" 'darcs'
			newpkgver=$(date +%Y%m%d)
		elif [[ -n ${_cvsroot} && -n ${_cvsmod} ]] ; then
			type -p cvs >/dev/null || return 0
			msg "$(gettext "Determining latest %s revision...")" 'cvs'
			newpkgver=$(date +%Y%m%d)
		elif [[ -n ${_gitroot} && -n ${_gitname} ]] ; then
			type -p git >/dev/null || return 0
			msg "$(gettext "Determining latest %s revision...")" 'git'
			newpkgver=$(date +%Y%m%d)
		elif [[ -n ${_svntrunk} && -n ${_svnmod} ]] ; then
			type -p svn >/dev/null || return 0
			msg "$(gettext "Determining latest %s revision...")" 'svn'
			newpkgver=$(LC_ALL=C svn info $_svntrunk | sed -n 's/^Last Changed Rev: \([0-9]*\)$/\1/p')
		elif [[ -n ${_bzrtrunk} && -n ${_bzrmod} ]] ; then
			type -p bzr >/dev/null || return 0
			msg "$(gettext "Determining latest %s revision...")" 'bzr'
			newpkgver=$(bzr revno ${_bzrtrunk})
		elif [[ -n ${_hgroot} && -n ${_hgrepo} ]] ; then
			type -p hg >/dev/null || return 0
			msg "$(gettext "Determining latest %s revision...")" 'hg'
			if [[ -d ./src/$_hgrepo ]] ; then
				cd ./src/$_hgrepo
				hg pull
				hg update
			else
				[[ ! -d ./src/ ]] && mkdir ./src/
				hg clone $_hgroot/$_hgrepo ./src/$_hgrepo
				cd ./src/$_hgrepo
			fi
			newpkgver=$(hg tip --template "{rev}")
			cd ../../
		fi

		if [[ -n $newpkgver ]]; then
			msg2 "$(gettext "Version found: %s")" "$newpkgver"
		fi

	else
		# Version number retrieved from fakeroot->makepkg argument
		newpkgver=$FORCE_VER
	fi
}

devel_update() {
	# This is lame, but if we're wanting to use an updated pkgver for
	# retrieving svn/cvs/etc sources, we'll update the PKGBUILD with
	# the new pkgver and then re-source it. This is the most robust
	# method for dealing with PKGBUILDs that use, e.g.:
	#
	#  pkgver=23
	#  ...
	#  _foo=pkgver
	#
	if [[ -n $newpkgver ]]; then
		if [[ $newpkgver != $pkgver ]]; then
			if [[ -f $BUILDFILE && -w $BUILDFILE ]]; then
				@SEDINPLACE@ "s/^pkgver=[^ ]*/pkgver=$newpkgver/" "$BUILDFILE"
				@SEDINPLACE@ "s/^pkgrel=[^ ]*/pkgrel=1/" "$BUILDFILE"
				source "$BUILDFILE"
			fi
		fi
	fi
}

backup_package_variables() {
	local var
	for var in ${splitpkg_overrides[@]}; do
		local indirect="${var}_backup"
		eval "${indirect}=(\"\${$var[@]}\")"
	done
}

restore_package_variables() {
	local var
	for var in ${splitpkg_overrides[@]}; do
		local indirect="${var}_backup"
		if [[ -n ${!indirect} ]]; then
			eval "${var}=(\"\${$indirect[@]}\")"
		else
			unset ${var}
		fi
	done
}

run_split_packaging() {
	local pkgname_backup=${pkgname[@]}
	for pkgname in ${pkgname_backup[@]}; do
		pkgdir="$pkgdir/$pkgname"
		mkdir -p "$pkgdir"
		chmod a-s "$pkgdir"
		backup_package_variables
		run_package $pkgname
		tidy_install
		create_package $pkgname
		restore_package_variables
		pkgdir="${pkgdir%/*}"
	done
	pkgname=${pkgname_backup[@]}
}

# Canonicalize a directory path if it exists
canonicalize_path() {
	local path="$1";

	if [[ -d $path ]]; then
		(
			cd "$path"
			pwd -P
		)
	else
		echo "$path"
	fi
}

# getopt like parser
parse_options() {
	local short_options=$1; shift;
	local long_options=$1; shift;
	local ret=0;
	local unused_options=""
	local i

	while [[ -n $1 ]]; do
		if [[ ${1:0:2} = '--' ]]; then
			if [[ -n ${1:2} ]]; then
				local match=""
				for i in ${long_options//,/ }; do
					if [[ ${1:2} = ${i//:} ]]; then
						match=$i
						break
					fi
				done
				if [[ -n $match ]]; then
					if [[ ${1:2} = $match ]]; then
						printf ' %s' "$1"
					else
						if [[ -n $2 ]]; then
							printf ' %s' "$1"
							shift
							printf " '%s'" "$1"
						else
							echo "makepkg: option '$1' $(gettext "requires an argument")" >&2
							ret=1
						fi
					fi
				else
					echo "makepkg: $(gettext "unrecognized option") '$1'" >&2
					ret=1
				fi
			else
				shift
				break
			fi
		elif [[ ${1:0:1} = '-' ]]; then
			for ((i=1; i<${#1}; i++)); do
				if [[ $short_options =~ ${1:i:1} ]]; then
					if [[ $short_options =~ ${1:i:1}: ]]; then
						if [[ -n ${1:$i+1} ]]; then
							printf ' -%s' "${1:i:1}"
							printf " '%s'" "${1:$i+1}"
						else
							if [[ -n $2 ]]; then
								printf ' -%s' "${1:i:1}"
								shift
								printf " '%s'" "${1}"
							else
								echo "makepkg: option $(gettext "requires an argument") -- '${1:i:1}'" >&2
								ret=1
							fi
						fi
						break
					else
						printf ' -%s' "${1:i:1}"
					fi
				else
					echo "makepkg: $(gettext "invalid option") -- '${1:i:1}'" >&2
					ret=1
				fi
			done
		else
			unused_options="${unused_options} '$1'"
		fi
		shift
	done

	printf " --"
	if [[ -n $unused_options ]]; then
		for i in ${unused_options[@]}; do
			printf ' %s' "$i"
		done
	fi
	if [[ -n $1 ]]; then
		while [[ -n $1 ]]; do
			printf " '%s'" "${1}"
			shift
		done
	fi
	printf "\n"

	return $ret
}

usage() {
	printf "makepkg (pacman) %s\n" "$myver"
	echo
	printf "$(gettext "Usage: %s [options]")\n" "$0"
	echo
	echo "$(gettext "Options:")"
	printf "$(gettext "  -A, --ignorearch Ignore incomplete arch field in %s")\n" "$BUILDSCRIPT"
	echo "$(gettext "  -c, --clean      Clean up work files after build")"
	echo "$(gettext "  -C, --cleancache Clean up source files from the cache")"
	echo "$(gettext "  -d, --nodeps     Skip all dependency checks")"
	echo "$(gettext "  -e, --noextract  Do not extract source files (use existing src/ dir)")"
	echo "$(gettext "  -f, --force      Overwrite existing package")"
	echo "$(gettext "  -g, --geninteg   Generate integrity checks for source files")"
	echo "$(gettext "  -h, --help       This help")"
	echo "$(gettext "  -i, --install    Install package after successful build")"
	echo "$(gettext "  -L, --log        Log package build process")"
	echo "$(gettext "  -m, --nocolor    Disable colorized output messages")"
	echo "$(gettext "  -o, --nobuild    Download and extract files only")"
	printf "$(gettext "  -p <file>        Use an alternate build script (instead of '%s')")\n" "$BUILDSCRIPT"
	echo "$(gettext "  -r, --rmdeps     Remove installed dependencies after a successful build")"
	echo "$(gettext "  -R, --repackage  Repackage contents of the package without rebuilding")"
	echo "$(gettext "  -s, --syncdeps   Install missing dependencies with pacman")"
	echo "$(gettext "  --allsource      Generate a source-only tarball including downloaded sources")"
	echo "$(gettext "  --asroot         Allow makepkg to run as root user")"
	printf "$(gettext "  --check          Run the check() function in the %s")\n" "$BUILDSCRIPT"
	printf "$(gettext "  --config <file>  Use an alternate config file (instead of '%s')")\n" "$confdir/makepkg.conf"
	printf "$(gettext "  --holdver        Prevent automatic version bumping for development %ss")\n" "$BUILDSCRIPT"
	printf "$(gettext "  --nocheck        Do not run the check() function in the %s")\n" "$BUILDSCRIPT"
	echo "$(gettext "  --pkg <list>     Only build listed packages from a split package")"
	echo "$(gettext "  --skipinteg      Do not fail when integrity checks are missing")"
	echo "$(gettext "  --source         Generate a source-only tarball without downloaded sources")"
	echo
	echo "$(gettext "These options can be passed to pacman:")"
	echo
	echo "$(gettext "  --noconfirm      Do not ask for confirmation when resolving dependencies")"
	echo "$(gettext "  --noprogressbar  Do not show a progress bar when downloading files")"
	echo
	printf "$(gettext "If -p is not specified, makepkg will look for '%s'")\n" "$BUILDSCRIPT"
	echo
}

version() {
	printf "makepkg (pacman) %s\n" "$myver"
	printf "$(gettext "\
Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>.\n\
Copyright (C) 2002-2006 Judd Vinet <jvinet@zeroflux.org>.\n\n\
This is free software; see the source for copying conditions.\n\
There is NO WARRANTY, to the extent permitted by law.\n")"
}

# PROGRAM START

# determine whether we have gettext; make it a no-op if we do not
if ! type -p gettext >/dev/null; then
	gettext() {
		echo "$@"
	}
fi

ARGLIST=("$@")

# Parse Command Line Options.
OPT_SHORT="AcCdefFghiLmop:rRsV"
OPT_LONG="allsource,asroot,ignorearch,check,clean,cleancache,nodeps"
OPT_LONG+=",noextract,force,forcever:,geninteg,help,holdver"
OPT_LONG+=",install,log,nocolor,nobuild,nocheck,pkg:,rmdeps"
OPT_LONG+=",repackage,skipinteg,source,syncdeps,version,config:"
# Pacman Options
OPT_LONG+=",noconfirm,noprogressbar"
OPT_TEMP="$(parse_options $OPT_SHORT $OPT_LONG "$@" || echo 'PARSE_OPTIONS FAILED')"
if [[ $OPT_TEMP = *'PARSE_OPTIONS FAILED'* ]]; then
	# This is a small hack to stop the script bailing with 'set -e'
	echo; usage; exit 1 # E_INVALID_OPTION;
fi
eval set -- "$OPT_TEMP"
unset OPT_SHORT OPT_LONG OPT_TEMP

while true; do
	case "$1" in
		# Pacman Options
		--noconfirm)      PACMAN_OPTS+=" --noconfirm" ;;
		--noprogressbar)  PACMAN_OPTS+=" --noprogressbar" ;;

		# Makepkg Options
		--allsource)      SOURCEONLY=2 ;;
		--asroot)         ASROOT=1 ;;
		-A|--ignorearch)  IGNOREARCH=1 ;;
		-c|--clean)       CLEANUP=1 ;;
		-C|--cleancache)  CLEANCACHE=1 ;;
		--check)          RUN_CHECK='y' ;;
		--config)         shift; MAKEPKG_CONF=$1 ;;
		-d|--nodeps)      NODEPS=1 ;;
		-e|--noextract)   NOEXTRACT=1 ;;
		-f|--force)       FORCE=1 ;;
		#hidden opt used by fakeroot call for svn/cvs/etc PKGBUILDs to set pkgver
		--forcever)       shift; FORCE_VER=$1;;
		-F)               INFAKEROOT=1 ;;
		-g|--geninteg)    GENINTEG=1 ;;
		--holdver)        HOLDVER=1 ;;
		-i|--install)     INSTALL=1 ;;
		-L|--log)         LOGGING=1 ;;
		-m|--nocolor)     USE_COLOR='n' ;;
		--nocheck)        RUN_CHECK='n' ;;
		-o|--nobuild)     NOBUILD=1 ;;
		-p)               shift; BUILDFILE=$1 ;;
		--pkg)            shift; PKGLIST=($1) ;;
		-r|--rmdeps)      RMDEPS=1 ;;
		-R|--repackage)   REPKG=1 ;;
		--skipinteg)      SKIPINTEG=1 ;;
		--source)         SOURCEONLY=1 ;;
		-s|--syncdeps)    DEP_BIN=1 ;;

		-h|--help)        usage; exit 0 ;; # E_OK
		-V|--version)     version; exit 0 ;; # E_OK

		--)               OPT_IND=0; shift; break;;
		*)                usage; exit 1 ;; # E_INVALID_OPTION
	esac
	shift
done

# preserve environment variables and canonicalize path
[[ -n ${PKGDEST} ]] && _PKGDEST=$(canonicalize_path ${PKGDEST})
[[ -n ${SRCDEST} ]] && _SRCDEST=$(canonicalize_path ${SRCDEST})
[[ -n ${SRCPKGDEST} ]] && _SRCPKGDEST=$(canonicalize_path ${SRCPKGDEST})

# default config is makepkg.conf
MAKEPKG_CONF=${MAKEPKG_CONF:-$confdir/makepkg.conf}

# Source the config file; fail if it is not found
if [[ -r $MAKEPKG_CONF ]]; then
	source "$MAKEPKG_CONF"
else
	error "$(gettext "%s not found.")" "$MAKEPKG_CONF"
	plain "$(gettext "Aborting...")"
	exit 1 # $E_CONFIG_ERROR
fi

# Source user-specific makepkg.conf overrides
if [[ -r ~/.makepkg.conf ]]; then
	source ~/.makepkg.conf
fi

# set pacman command if not already defined
PACMAN=${PACMAN:-pacman}

# check if messages are to be printed using color
unset ALL_OFF BOLD BLUE GREEN RED YELLOW
if [[ -t 2 && ! $USE_COLOR = "n" && $(check_buildenv color) = "y" ]]; then
	# prefer terminal safe colored and bold text when tput is supported
	if tput setaf 0 &>/dev/null; then
		ALL_OFF="$(tput sgr0)"
		BOLD="$(tput bold)"
		BLUE="${BOLD}$(tput setaf 4)"
		GREEN="${BOLD}$(tput setaf 2)"
		RED="${BOLD}$(tput setaf 1)"
		YELLOW="${BOLD}$(tput setaf 3)"
	else
		ALL_OFF="\e[1;0m"
		BOLD="\e[1;1m"
		BLUE="${BOLD}\e[1;34m"
		GREEN="${BOLD}\e[1;32m"
		RED="${BOLD}\e[1;31m"
		YELLOW="${BOLD}\e[1;33m"
	fi
fi
readonly ALL_OFF BOLD BLUE GREEN RED YELLOW

# override settings with an environment variable for batch processing
PKGDEST=${_PKGDEST:-$PKGDEST}
PKGDEST=${PKGDEST:-$startdir} #default to $startdir if undefined
if [[ ! -w $PKGDEST ]]; then
	error "$(gettext "You do not have write permission to store packages in %s.")" "$PKGDEST"
	plain "$(gettext "Aborting...")"
	exit 1
fi

SRCDEST=${_SRCDEST:-$SRCDEST}
SRCDEST=${SRCDEST:-$startdir} #default to $startdir if undefined
if [[ ! -w $SRCDEST ]] ; then
	error "$(gettext "You do not have write permission to store downloads in %s.")" "$SRCDEST"
	plain "$(gettext "Aborting...")"
	exit 1
fi

SRCPKGDEST=${_SRCPKGDEST:-$SRCPKGDEST}
SRCPKGDEST=${SRCPKGDEST:-$startdir} #default to $startdir if undefined


if (( HOLDVER )) && [[ -n $FORCE_VER ]]; then
	# The '\\0' is here to prevent gettext from thinking --holdver is an option
	error "$(gettext "\\0--holdver and --forcever cannot both be specified" )"
	exit 1
fi

if (( CLEANCACHE )); then
	#fix flyspray feature request #5223
	if [[ -n $SRCDEST && ! $SRCDEST -ef "${startdir}" ]]; then
		msg "$(gettext "Cleaning up ALL files from %s.")" "$SRCDEST"
		echo -n "$(gettext "    Are you sure you wish to do this? ")"
		echo -n "$(gettext "[y/N]")"
		read answer
		answer=$(tr '[:lower:]' '[:upper:]' <<< "$answer")
		if [[ $answer = $(gettext YES) || $answer = $(gettext Y) ]]; then
			rm "$SRCDEST"/*
			if (( $? )); then
				error "$(gettext "Problem removing files; you may not have correct permissions in %s")" "$SRCDEST"
				exit 1
			else
				# removal worked
				msg "$(gettext "Source cache cleaned.")"
				exit 0
			fi
		else
			# answer = no
			msg "$(gettext "No files have been removed.")"
			exit 0
		fi
	else
		# $SRCDEST is $startdir, two possibilities
		error "$(gettext "Source destination must be defined in %s.")" "$MAKEPKG_CONF"
		plain "$(gettext "In addition, please run makepkg -C outside of your cache directory.")"
		exit 1
	fi
fi

if (( ! INFAKEROOT )); then
	if (( EUID == 0 && ! ASROOT )); then
		# Warn those who like to live dangerously.
		error "$(gettext "Running makepkg as root is a BAD idea and can cause")"
		plain "$(gettext "permanent, catastrophic damage to your system. If you")"
		plain "$(gettext "wish to run as root, please use the --asroot option.")"
		exit 1 # $E_USER_ABORT
	elif (( EUID > 0 && ASROOT )); then
		# Warn those who try to use the --asroot option when they are not root
		error "$(gettext "The --asroot option is meant for the root user only.")"
		plain "$(gettext "Please rerun makepkg without the --asroot flag.")"
		exit 1 # $E_USER_ABORT
	elif [[ $(check_buildenv fakeroot) = "y" ]] && (( EUID > 0 )); then
		if ! type -p fakeroot >/dev/null; then
			error "$(gettext "Fakeroot must be installed if using the 'fakeroot' option")"
			plain "$(gettext "in the BUILDENV array in %s.")" "$MAKEPKG_CONF"
			exit 1
		fi
	elif (( EUID > 0 )); then
		warning "$(gettext "Running makepkg as an unprivileged user will result in non-root")"
		plain "$(gettext "ownership of the packaged files. Try using the fakeroot environment by")"
		plain "$(gettext "placing 'fakeroot' in the BUILDENV array in %s.")" "$MAKEPKG_CONF"
		sleep 1
	fi
else
	if [[ -z $FAKEROOTKEY ]]; then
		error "$(gettext "Do not use the '-F' option. This option is only for use by makepkg.")"
		exit 1 # TODO: error code
	fi
fi

# check for sudo if we will need it during makepkg execution
if (( ! ( ASROOT || INFAKEROOT ) && ( DEP_BIN || RMDEPS || INSTALL ) )); then
	if ! type -p sudo >/dev/null; then
		warning "$(gettext "Sudo can not be found. Will use su to acquire root privileges.")"
	fi
fi

unset pkgname pkgbase pkgver pkgrel epoch pkgdesc url license groups provides
unset md5sums replaces depends conflicts backup source install changelog build
unset makedepends optdepends options noextract

BUILDFILE=${BUILDFILE:-$BUILDSCRIPT}
if [[ ! -f $BUILDFILE ]]; then
	if [[ -t 0 ]]; then
		error "$(gettext "%s does not exist.")" "$BUILDFILE"
		exit 1
	else
		# PKGBUILD passed through a pipe
		BUILDFILE=/dev/stdin
		source "$BUILDFILE"
	fi
else
	crlftest=$(file "$BUILDFILE" | grep -F 'CRLF' || true)
	if [[ -n $crlftest ]]; then
		error "$(gettext "%s contains CRLF characters and cannot be sourced.")" "$BUILDFILE"
		exit 1
	fi

	if [[ ${BUILDFILE:0:1} != "/" ]]; then
		BUILDFILE="$startdir/$BUILDFILE"
	fi
	source "$BUILDFILE"
fi

# set defaults if they weren't specified in buildfile
pkgbase=${pkgbase:-${pkgname[0]}}
epoch=${epoch:-0}

if (( GENINTEG )); then
	mkdir -p "$srcdir"
	chmod a-s "$srcdir"
	cd "$srcdir"
	download_sources
	generate_checksums
	exit 0 # $E_OK
fi

# check the PKGBUILD for some basic requirements
check_sanity || exit 1

# We need to run devel_update regardless of whether we are in the fakeroot
# build process so that if the user runs makepkg --forcever manually, we
# 1) output the correct pkgver, and 2) use the correct filename when
# checking if the package file already exists - fixes FS #9194
devel_check
devel_update

if (( ${#pkgname[@]} > 1 )); then
	SPLITPKG=1
fi

# test for available PKGBUILD functions
if declare -f build >/dev/null; then
	BUILDFUNC=1
fi
if declare -f check >/dev/null; then
	# "Hide" check() function if not going to be run
	if [[ $RUN_CHECK = 'y' || (! $(check_buildenv check) = "n" &&  ! $RUN_CHECK = "n") ]]; then
		CHECKFUNC=1
	fi
fi
if declare -f package >/dev/null; then
	PKGFUNC=1
elif [[ $SPLITPKG -eq 0 ]] && declare -f package_${pkgname} >/dev/null; then
	SPLITPKG=1
fi

if [[ -n "${PKGLIST[@]}" ]]; then
	unset pkgname
	pkgname=("${PKGLIST[@]}")
fi

if (( ! SPLITPKG )); then
	fullver=$(get_full_version $epoch $pkgver $pkgrel)
	if [[ -f $PKGDEST/${pkgname}-${fullver}-${CARCH}${PKGEXT} \
	     || -f $PKGDEST/${pkgname}-${fullver}-any${PKGEXT} ]] \
			 && ! (( FORCE || SOURCEONLY || NOBUILD )); then
		if (( INSTALL )); then
			warning "$(gettext "A package has already been built, installing existing package...")"
			install_package
			exit $?
		else
			error "$(gettext "A package has already been built. (use -f to overwrite)")"
			exit 1
		fi
	fi
else
	allpkgbuilt=1
	somepkgbuilt=0
	for pkg in ${pkgname[@]}; do
		# TODO: this wasn't properly fixed in commit 2020e629
		fullver=$(get_full_version $epoch $pkgver $pkgrel)
		if [[ -f $PKGDEST/${pkg}-${fullver}-${CARCH}${PKGEXT} \
		     || -f $PKGDEST/${pkg}-${fullver}-any${PKGEXT} ]]; then
			somepkgbuilt=1
		else
			allpkgbuilt=0
		fi
	done
	if ! (( FORCE || SOURCEONLY || NOBUILD )); then
		if (( allpkgbuilt )); then
			if (( INSTALL )); then
				warning "$(gettext "The package group has already been built, installing existing packages...")"
				install_package
				exit $?
			else
				error "$(gettext "The package group has already been built. (use -f to overwrite)")"
				exit 1
			fi
		fi
		if (( somepkgbuilt )); then
			error "$(gettext "Part of the package group has already been built. (use -f to overwrite)")"
			exit 1
		fi
	fi
	unset allpkgbuilt somepkgbuilt
fi

# Run the bare minimum in fakeroot
if (( INFAKEROOT )); then
	if (( ! SPLITPKG )); then
		if (( ! PKGFUNC )); then
			if (( ! REPKG )); then
				if (( BUILDFUNC )); then
					run_build
					(( CHECKFUNC )) && run_check
					tidy_install
				fi
			else
				warning "$(gettext "Repackaging without the use of a package() function is deprecated.")"
				plain "$(gettext "File permissions may not be preserved.")"
			fi
		else
			run_package
			tidy_install
		fi
		create_package
	else
		run_split_packaging
	fi

	msg "$(gettext "Leaving fakeroot environment.")"
	exit 0 # $E_OK
fi

fullver=$(get_full_version $epoch $pkgver $pkgrel)
msg "$(gettext "Making package: %s")" "$pkgbase $fullver ($(date))"

# if we are creating a source-only package, go no further
if (( SOURCEONLY )); then
	if [[ -f $SRCPKGDEST/${pkgbase}-${fullver}${SRCEXT} ]] \
	     && (( ! FORCE )); then
		error "$(gettext "A source package has already been built. (use -f to overwrite)")"
		exit 1
	fi
	create_srcpackage
	msg "$(gettext "Source package created: %s")" "$pkgbase ($(date))"
	exit 0
fi

if (( NODEPS || ( (NOBUILD || REPKG) && !DEP_BIN ) )); then
	# no warning message needed for nobuild, repkg
	if (( NODEPS || ( REPKG && PKGFUNC ) )); then
		warning "$(gettext "Skipping dependency checks.")"
	fi
elif type -p "${PACMAN%% *}" >/dev/null; then
	if (( RMDEPS )); then
		original_pkglist=($(run_pacman -Qq))    # required by remove_dep
	fi
	deperr=0

	msg "$(gettext "Checking runtime dependencies...")"
	resolve_deps ${depends[@]} || deperr=1

	msg "$(gettext "Checking buildtime dependencies...")"
	resolve_deps ${makedepends[@]} || deperr=1

	if (( CHECKFUNC )); then
		resolve_deps ${checkdepends[@]} || deperr=1
	fi

	if (( RMDEPS )); then
		current_pkglist=($(run_pacman -Qq))    # required by remove_deps
	fi

	if (( deperr )); then
		error "$(gettext "Could not resolve all dependencies.")"
		exit 1
	fi
else
	warning "$(gettext "%s was not found in PATH; skipping dependency checks.")" "${PACMAN%% *}"
fi

# ensure we have a sane umask set
umask 0022

# get back to our src directory so we can begin with sources
mkdir -p "$srcdir"
chmod a-s "$srcdir"
cd "$srcdir"

if (( NOEXTRACT )); then
	warning "$(gettext "Skipping source retrieval        -- using existing src/ tree")"
	warning "$(gettext "Skipping source integrity checks -- using existing src/ tree")"
	warning "$(gettext "Skipping source extraction       -- using existing src/ tree")"

	if (( NOEXTRACT )) && [[ -z $(ls "$srcdir" 2>/dev/null) ]]; then
		error "$(gettext "The source directory is empty, there is nothing to build!")"
		plain "$(gettext "Aborting...")"
		exit 1
	fi
elif (( REPKG )); then
	if (( ! PKGFUNC && ! SPLITPKG )) \
	     && [[ ! -d $pkgdir || -z $(ls "$pkgdir" 2>/dev/null) ]]; then
		error "$(gettext "The package directory is empty, there is nothing to repackage!")"
		plain "$(gettext "Aborting...")"
		exit 1
	fi
else
	download_sources
	if (( ! SKIPINTEG )); then
		check_checksums
	else
		warning "$(gettext "Skipping integrity checks.")"
	fi
	extract_sources
fi

if (( NOBUILD )); then
	msg "$(gettext "Sources are ready.")"
	exit 0 #E_OK
else
	# check for existing pkg directory; don't remove if we are repackaging
	if [[ -d $pkgdir ]] && (( ! REPKG || PKGFUNC || SPLITPKG )); then
		msg "$(gettext "Removing existing pkg/ directory...")"
		rm -rf "$pkgdir"
	fi
	mkdir -p "$pkgdir"
	chmod a-s "$pkgdir"
	cd "$startdir"

	# if we are root or if fakeroot is not enabled, then we don't use it
	if [[ $(check_buildenv fakeroot) != "y" ]] || (( EUID == 0 )); then
		if (( ! REPKG )); then
			devel_update
			(( BUILDFUNC )) && run_build
			(( CHECKFUNC )) && run_check
		fi
		if (( ! SPLITPKG )); then
			if (( PKGFUNC )); then
				run_package
				tidy_install
			else
				if (( ! REPKG )); then
					tidy_install
				else
					warning "$(gettext "Repackaging without the use of a package() function is deprecated.")"
					plain "$(gettext "File permissions may not be preserved.")"
				fi
			fi
			create_package
		else
			run_split_packaging
		fi
	else
		if (( ! REPKG && ( PKGFUNC || SPLITPKG ) )); then
			devel_update
			(( BUILDFUNC )) && run_build
			(( CHECKFUNC )) && run_check
			cd "$startdir"
		fi

		msg "$(gettext "Entering fakeroot environment...")"

		if [[ -n $newpkgver ]]; then
			fakeroot -- $0 --forcever $newpkgver -F "${ARGLIST[@]}" || exit $?
		else
			fakeroot -- $0 -F "${ARGLIST[@]}" || exit $?
		fi
	fi
fi

fullver=$(get_full_version $epoch $pkgver $pkgrel)
msg "$(gettext "Finished making: %s")" "$pkgbase $fullver ($(date))"

install_package

exit 0 #E_OK

# vim: set ts=2 sw=2 noet: