#!/usr/local/bin/cbsd
#v10.0.3
CBSDMODULE="build"
MYARG=""
MYOPTARG="ver arch target_arch maxjobs clean name basename ccache notify stable emulator"
MYDESC="Build kernel from sources"
ADDHELP="

${H3_COLOR}Description${N0_COLOR}:

Build/compile kernel from source tree. To compile the kernel, you first need to get 
'base' and source code, e.g.: 'cbsd srcup' + 'cbsd world' or via 'cbsd repo'.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}arch=${N0_COLOR}         - <name>, use non-native architectures;
 ${N2_COLOR}basename=${N0_COLOR}     - Prefix for directory name, can be used for jail as alternative base;
 ${N2_COLOR}destdir${N0_COLOR}       - <path> - alternative DESTDIR= path instead of ~cbsd/basejail/;
 ${N2_COLOR}name=${N0_COLOR}         - name of the kernel, default: 'GENERIC';
 ${N2_COLOR}nice=${N0_COLOR}         - num: overwrite default nice: '19';
 ${N2_COLOR}target_arch=${N0_COLOR}  - <name>, build non-native target arch;
 ${N2_COLOR}ver=${N0_COLOR}          - set version: '14.1', '14.2';
                   when version without minor version: e.g:
                  '14' or '15' - you will receive RELENG (stable=1), not release.

${H3_COLOR}Examples${N0_COLOR}:

 # cbsd buildkernel
 # cbsd buildkernel destdir=/tmp/testkernel name=CBSD
 # cbsd buildkernel ver=14.1 arch=arm64 target_arch=aarch64
 # cbsd buildkernel ver=15.0 arch=riscv target_arch=riscv64

${H3_COLOR}See also${N0_COLOR}:

  cbsd installkernel --help
  cbsd srcup --help
  cbsd kernels --help
  cbsd mkdistribution --help
  cbsd install-pkg-world --help

"

. ${subrdir}/nc.subr
name=
oname=
over=
oarch=
ver=
arch=
nice=
onice=
. ${cbsdinit}

[ -n "${arch}" ] && oarch="${arch}"
[ -n "${ver}" ] && over="${ver}"
[ -n "${name}" ] && oname="${name}"
[ -n "${nice}" ] && onice="${nice}"

[ -z "${nice}" ] && nice="19"
[ -z "${name}" ] && name="GENERIC"

. ${subrdir}/build.subr

# auto-detect for stable/release
strpos --str="${ver}" --search="."
pos=$?
if [ ${pos} -eq 0 ]; then
	stable=1
	ostable=1
else
	stable=0
	ostable=0
fi

. ${subrdir}/distccache.subr
. ${subrdir}/mailtools.subr
readconf buildworld.conf
. ${system}
. ${subrdir}/universe.subr
. ${subrdir}/emulator.subr
readconf srcup.conf

init_distcc
init_notify
init_target_arch
init_srcdir
init_supported_arch

[ -z "${emulator}" ] && emulator="jail"

#init_usermode_emul

if [ "${ccache}" = "1"  ]; then
	ccache_prefix="cbsd buildworld ${ver} ${arch} ${target_arch} ${basename}"
	ccache_dir="/var/cache/ccache"
	init_ccache_dir
	export CCACHE_DIR=${ccache_realdir}

	if ! ccache_check; then
		ccache=0
	fi
else
	ccache=0
fi

init_basedir

if [ ! -d "${BASE_DIR}" -o ! -f "${BASE_DIR}/bin/sh" ]; then
	${ECHO} "${N1_COLOR}FreeBSD base on ${N2_COLOR}${BASE_DIR}${N1_COLOR} is missing${N0_COLOR}"
	${ECHO} "${N1_COLOR}Use ${N2_COLOR}cbsd world${N1_COLOR} to compile from the source${N0_COLOR}"
	${ECHO} "${N2_COLOR}cbsd repo action=get sources=base${N1_COLOR} to obtain it from repository.${N0_COLOR}"
	exit 1
fi

init_make_flags

LOCKFILE=${ftmpdir}/$( ${miscdir}/cbsd_md5 ${MAKEOBJDIRPREFIX} ).lock

kernel_conf="${platform}-kernel-${name}-${arch}-${ver}"

if [ -f "${etcdir}/${kernel_conf}" ]; then
	kernel_conf_path="${etcdir}/${kernel_conf}"
else
	kernel_conf_path="${etcdir}/defaults/${kernel_conf}"
fi

[ ! -f "${kernel_conf_path}" ] && err 1 "${N1_COLOR}No such config ${kernel_conf_path} in: ${N2_COLOR}${etcdir}${N0_COLOR}"

## preparing chroot
TMPDST="${basejaildir}/tempbase.$$"
${MKDIR_CMD} -p ${TMPDST}

[ $notify -eq 1 ] && BLDLOG="${tmpdir}/build.$$.log"

case "${platform}" in
	"DragonFly")
		DESTCONF="${SRC_DIR}/sys/config/${name}.CBSD"
		;;
	*)
		DESTCONF="${SRC_DIR}/sys/${arch}/conf/${name}.CBSD"
		;;
esac

makelock $LOCKFILE "${RM_CMD} -f ${DESTCONF} && ${UMOUNT_CMD} -f ${TMPDST}${MAKEOBJDIRPREFIX} && ${UMOUNT_CMD} -f ${TMPDST}/dev && ${UMOUNT_CMD} -f ${TMPDST}/${SRC_DIR} && ${CHFLAGS_CMD} -R noschg ${TMPDST} && ${RM_CMD} -rf ${TMPDST} && ${RM_CMD} -f ${BLDLOG}"

baserw=1
populate_cdir ${BASE_DIR} ${TMPDST}
${CP_CMD} ${kernel_conf_path} ${DESTCONF}

# place for rewrite to mountbase from system.subr
${MKDIR_CMD} -p ${TMPDST}/${SRC_DIR}
${MOUNT_NULL_CMD} -o ro ${SRC_DIR} ${TMPDST}/${SRC_DIR}

${MKDIR_CMD} -p ${MAKEOBJDIRPREFIX} ${TMPDST}${MAKEOBJDIRPREFIX}

${MKDIR_CMD} -p ${TMPDST}${etcdir}
[ -f "${__MAKE_CONF}" ] && ${CP_CMD} ${__MAKE_CONF} ${TMPDST}${etcdir}
[ -f "${SRCCONF}" ] && ${CP_CMD} ${SRCCONF} ${TMPDST}${etcdir}
${MOUNT_NULL_CMD} ${MAKEOBJDIRPREFIX} ${TMPDST}${MAKEOBJDIRPREFIX}
${MOUNT_CMD} -t devfs devfs ${TMPDST}/dev
#

st_time=$( ${DATE_CMD} +%s )

# chroot not for cross-arch build
if [ ${notify} -eq 1 ]; then
	[ -z "$TAILSTRING" ] && TAILSTRING=50
	script ${BLDLOG} nice -n ${nice} ${IDLE_IONICE} ${CHROOT_CMD} ${TMPDST} ${MAKE_CMD} ${NUMJOBS} -C ${SRC_DIR} buildkernel KERNCONF=${name}.CBSD ${NOCLEANUP} TARGET=${arch} TARGET_ARCH="${target_arch}"
	res=$?
else
	#${CHROOT_CMD} ${TMPDST} nice -n ${nice} ${IDLE_IONICE} ${MAKE_CMD} ${NUMJOBS} -C ${SRC_DIR} buildkernel KERNCONF=${name}.CBSD ${NOCLEANUP} TARGET=${arch} TARGET_ARCH="${target_arch}"
	nice -n ${nice} ${IDLE_IONICE} ${MAKE_CMD} ${NUMJOBS} -C ${SRC_DIR} buildkernel KERNCONF=${name}.CBSD ${NOCLEANUP} TARGET=${arch} TARGET_ARCH="${target_arch}"
	res=$?
fi

end_time=$( ${DATE_CMD} +%s )
run_time=$(( end_time - st_time ))
. ${subrdir}/time.subr
diff_time=$( displaytime ${run_time} )

if [ ${notify} -eq 1 ]; then
${CAT_CMD} >> ${BLDLOG} << EOF
Start build date: ${st_time}
End build date: ${end_time}
Runtime: ${diff_time}
EOF
fi

${CAT_CMD} <<EOF
Start build date: ${st_time}
End build date: ${end_time}
Runtime: ${diff_time}
EOF

init_scm_and_version

if [ ${res} -ne 0 ]; then
	[ ${notify} -eq 1 ] && send_notification -s "[CBSD ${nodename}] buildkernel ${name} $basename $ver $arch ${target_arch} r${svnrev} failed." -b "`tail -n${TAILSTRING} ${BLDLOG}`"
	exit 1
fi

if [ ${res} -eq 0 -a $notify -eq 1 ]; then
	send_notification -s "[CBSD ${nodename}] buildkernel ${name} $basename $ver $arch ${target_arch} r${svnrev} complete in ${diff_time}" -f ${BLDLOG}
	return 0
fi

exit 0
