#!/bin/sh
# $NetBSD: pkg-build,v 1.31 2016/12/18 09:36:38 joerg Exp $
#
# Copyright (c) 2007, 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
# All rights reserved.
#
# This code was developed as part of Google's Summer of Code 2007 program.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

. ${PBULK_CONF:-/opt/tools/etc/pbulk.conf}

if [ "${config_version}" != "0.68" ]; then
	echo "Your configuration has version ${config_version}."
	echo "This version of pbulk expects version 0.68."
	exit 1
fi

default_sync_package() {
	mkdir -p ${packages}/All
	cp "$1" "${packages}/All/${pkgname}${pkg_sufx}"
}

logpkgtime() {
	stop_time=`date '+%s'`
	build_time=`expr ${stop_time} - ${start_time}`
	mkdir -p ${packages}/pkgtimes
	echo "${build_time}" >${packages}/pkgtimes/${pkgname}.pkgtime
}

cleanup() {
	logpkgtime
	if [ -n "${local_bulklog}" ]; then
		mkdir -p ${bulklog}
		mv ${logpkgdir} ${bulklog}/${pkgname}
	fi
	if [ "$keep_wrkdir" = yes ]; then
		${make} pbulk-save-wrkdir INTO=${bulklog}/${pkgname}/wrkdir.tar.gz TAR="${tar}"
	fi
	if [ "$keep_prefix" = yes ] && [ -f ${bulklog}/${pkgname}/install.log ]; then
		if [ "$cross_compile" != "no" ]; then
			cur_destdir=${target_destdir}
		else
			cur_destdir=
		fi
		${tar} -czf ${bulklog}/${pkgname}/prefix.tar.gz ${cur_destdir}${prefix}
	fi
	${make} clean > /dev/null 2>&1 || true
	${sync_buildlog} ${bulklog} ${pkgname}
	exit 1
}

run_direct() { "$@"; }
run_su() { su ${unprivileged_user} -c '"$@"' make "$@"; }

run_make() {
	local run_cmd
	run_cmd=$1
	shift
	${run_cmd} ${make} "$@" \
		BATCH=1 \
		DEPENDS_TARGET=/nonexistent \
		${MAKE_FLAGS} \
		WRKLOG=${logpkgdir}/work.log
}

run_usergroup() {
	case "${usergroup_phase}" in
	*configure)
		[ "$1" != "configure" ] || ${make} create-usergroup clean
		;;
	*build)
		[ "$1" != "build" ] || ${make} create-usergroup
		;;
	pre-install)
		[ "$1" != "install" ] || ${make} create-usergroup
		;;
	esac
}

while read build_info_line; do
	case "${build_info_line}" in
	PKGNAME=*)
		pkgname=${build_info_line#PKGNAME=}
		;;
	PKG_LOCATION=*)
		pkgdir=${build_info_line#PKG_LOCATION=}
		;;
	DEPENDS=*)
		dependencies=${build_info_line#DEPENDS=}
		;;
	CATEGORIES=*)
		categories=${build_info_line#CATEGORIES=}
		;;
	MULTI_VERSION=*)
		MAKE_FLAGS=${build_info_line#MULTI_VERSION=}
		;;
	USE_DESTDIR=*)
		use_destdir=${build_info_line#USE_DESTDIR=}
		;;
	BOOTSTRAP_PKG=*)
		is_bootstrap=${build_info_line#BOOTSTRAP_PKG=}
		;;
	USERGROUP_PHASE=*)
		usergroup_phase=${build_info_line#USERGROUP_PHASE=}
		;;
	NO_BIN_ON_FTP=*)
		restricted=${build_info_line#NO_BIN_ON_FTP=}
		;;
	esac
done

if [ "$use_unprivileged_checksum" != "no" ]; then
	run_checksum=run_su
else
	run_checksum=run_direct
fi

# Sometimes writing logs to NFS can cause issues, support writing to a local
# bulklog directory before moving to NFS at the end.
if [ -n "${local_bulklog}" ]; then
	logpkgdir="${local_bulklog}/${pkgname}"
else
	logpkgdir="${bulklog}/${pkgname}"
fi

if [ "$use_destdir" = user-destdir ]; then
	run_build=run_su
	run_install=run_su
else
	run_build=run_su
	run_install=run_direct
fi

if [ `/usr/bin/id -u` -ne 0 ]; then
	run_checksum=run_direct
	run_build=run_direct
	run_install=run_direct
fi

# Attempt to move the pre-build status file into place.  If we're successful
# we are the first build and we can now log the remaining details.
ret=`mv ${loc}/status.pre-build ${loc}/status 2>/dev/null; echo $?`
if [ ${ret} -eq 0 ]; then
	/opt/tools/libexec/pbulk/client-clean
	opsys=`cd ${pkgsrc}/pkgtools/pkg_install && ${make} show-var VARNAME=OPSYS`
	opver=`cd ${pkgsrc}/pkgtools/pkg_install && ${make} show-var VARNAME=OS_VERSION`
	# Check if it is an OS with variants where we would rather use the
	# variant name and version rather than common name and version
	case "$opsys" in
	SunOS | Cygwin | SCO_SV)
		opvar=`cd ${pkgsrc}/pkgtools/pkg_install && ${make} show-var VARNAME=OS_VARIANT`
		case "$opsys" in
		Cygwin | SCO_SV)
			opsys=$opvar
			;;
		SunOS)
			if [ -n "$opvar" ]; then
				opsys=$opvar
				opver=`cd ${pkgsrc}/pkgtools/pkg_install && ${make} show-var VARNAME=LOWER_VARIANT_VERSION`
			fi
			;;
		esac
		;;
	esac
	platform=`cd ${pkgsrc}/pkgtools/pkg_install && ${make} show-var VARNAME=MACHINE_ARCH`
	compiler=`cd ${pkgsrc}/pkgtools/pkg_install && ${make} show-var VARNAME=PKGSRC_COMPILER`

	echo "COMPILER=${compiler}" >> ${loc}/status
	if [ -n "${report_platform}" ]; then
		echo "PLATFORM=${report_platform}" >> ${loc}/status
	else
		echo "PLATFORM=${opsys} ${opver}/${platform}" >> ${loc}/status
	fi

	if [ -s ${pkgsrc}/README.push ]; then
		echo "DESCRIPTION=`head -1 ${pkgsrc}/README.push`" >> ${loc}/status
	fi
fi

${pkg_up_to_date_script} ${pkgname} ${dependencies} && exit 0

# Ensure we start with a clean passwd/group.
if [ `uname` != "Darwin" ]; then
	for file in group passwd shadow user_attr; do
		if [ -f ${loc}/${file} ]; then
			cp -p ${loc}/${file} /etc/${file}
		elif [ -f /etc/${file} ]; then
			cp -p /etc/${file} ${loc}/${file}
		fi
	done
fi

set -e

/opt/tools/libexec/pbulk/client-clean

# Create the output directory and clean it up
rm -rf ${bulklog}/${pkgname}
mkdir -p ${logpkgdir}
rm -f ${logpkgdir}/*

# Ensure we log any failures from this script itself, otherwise it is very
# difficult to debug.
exec >${logpkgdir}/pkg-build.log 2>&1
set -x

touch ${logpkgdir}/work.log
/usr/sbin/chown ${unprivileged_user} ${logpkgdir}/work.log

pkg_add_normal() {
	PKG_PATH=${packages}/All ${pkg_add} -K ${cur_pkgdb} "$@"
}

pkg_add_cross() {
	PKG_PATH=${packages}/All ${pkg_add} -K ${cur_pkgdb} \
	    -m ${target_arch} -I -p ${target_destdir}${prefix} "$@"
	echo "Fixing recorded cwd..."
	${pkg_info} -K ${target_destdir}${pkgdb} | while read pkg junk; do
		${sed} -e 's|@cwd '"${target_destdir}"'|@cwd |' \
		    ${cur_pkgdb}/"${pkg}"/+CONTENTS > \
		    ${cur_pkgdb}/"${pkg}"/+CONTENTS.tmp
		mv ${cur_pkgdb}/"${pkg}"/+CONTENTS.tmp \
		    ${cur_pkgdb}/"${pkg}"/+CONTENTS
	done
}

if [ "$cross_compile" != "no" ]; then
	pkg_add_cmd=pkg_add_cross
	cur_pkgdb="${target_destdir}${pkgdb}"
else
	pkg_add_cmd=pkg_add_normal
	cur_pkgdb="${pkgdb}"
fi

# Save package start time
start_time=`date '+%s'`

# Go to target directory
cd ${pkgsrc}/${pkgdir}
# Clean build area, just in case
${make} clean > ${logpkgdir}/pre-clean.log 2>&1 || cleanup
# Install all dependencies the package said it would need
if [ ! -z "$dependencies" ]; then
	${pkg_add_cmd} $dependencies > ${logpkgdir}/depends.log 2>&1 || cleanup
fi
# Build package, create a separate log file for each major phase
run_make ${run_checksum} checksum > ${logpkgdir}/checksum.log 2>&1 || cleanup
run_usergroup configure > ${logpkgdir}/configure.log 2>&1 || cleanup
run_make ${run_build} configure >> ${logpkgdir}/configure.log 2>&1 || cleanup
run_usergroup build> ${logpkgdir}/build.log 2>&1 || cleanup
run_make ${run_build} all >> ${logpkgdir}/build.log 2>&1 || cleanup
run_usergroup install > ${logpkgdir}/install.log 2>&1 || cleanup
run_make ${run_install} stage-install >> ${logpkgdir}/install.log 2>&1 || cleanup
run_make run_direct stage-package-create > ${logpkgdir}/package.log 2>&1 || cleanup

pkgfile=$(run_make run_direct show-var VARNAME=STAGE_PKGFILE)

# Add the package once to test install rules.  This is not done for
# potential bootstrap packages as they might already be installed.
if [ -z "${is_bootstrap}" ]; then
	if ! ${pkg_add_cmd} ${pkgfile} \
	    >> ${logpkgdir}/package.log 2>&1; then
		cleanup
	fi
fi

# Test uninstall rules. This is not for cross-compiling as the install script
# is not run in that case anyway. This is also not done for packages marked as
# part of the bootstrap, those have the preserve flag set.
if [ "$cross_compile" = "no" ] && \
   [ -z "${is_bootstrap}" ]; then
	${pkg_delete} -K ${cur_pkgdb} ${pkgname} > ${logpkgdir}/deinstall.log 2>&1 || cleanup
fi

# Comment the following out if you want to test all deinstall scripts.
# This is quite expensive and mostly redundant, so it is disabled by default.
#${pkg_delete} -r \* > /dev/null 2>&1 || cleanup

${sync_package} ${pkgfile} ${pkgname} "${categories}" || cleanup

# Clean build area
${make} clean > ${logpkgdir}/clean.log 2>&1 || cleanup

# Save build runtime
logpkgtime

# Save a SHA512 sum of the package (if not restricted), saves doing all of
# them single-threaded at the end of a bulk build and avoids re-computing for
# packages we have already built.
if [ -z "${restricted}" ]; then
	mkdir -p ${packages}/checksums ${packages}/pkginfo
	(
		cd ${packages}
		${digest} SHA512 All/${pkgname}${pkg_sufx} \
		    > ${packages}/checksums/${pkgname}.sha512 || cleanup
		${pkg_info} -X All/${pkgname}${pkg_sufx} \
		    > ${packages}/pkginfo/${pkgname}.pkginfo || cleanup
		${pkg_info} -L All/${pkgname}${pkg_sufx} \
		    > ${packages}/pkginfo/${pkgname}.pkglist || cleanup
	)
fi

# Cleanup build logs on success
rm -R ${logpkgdir}
