#!/usr/local/bin/cbsd
#v11.0.6
MYARG=""
MYOPTARG="dst patch rev scmbase ver"
MYDESC="Update base source tree in ~cbsd/src directory"
ADDHELP="

${H3_COLOR}Description${N0_COLOR}:

CBSD can get a working basejail directory in several ways, one of then is compilation 
from source codes via 'cbsd buildworld'. 'srcup' script used to get source codes 
from official sources.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}dst=${N0_COLOR}     - alternative dst dir;
 ${N2_COLOR}patch=${N0_COLOR}   - apply CBSD patchet;
 ${N2_COLOR}rev=${N0_COLOR}     - XXX where XXX - svn revision;
 ${N2_COLOR}scmbase=${N0_COLOR} - alternative svn base URL;
 ${N2_COLOR}ver=${N0_COLOR}     - 'head' for current, or e.g.: '13.1' or 'ver=13' for stable;

${H3_COLOR}Examples${N0_COLOR}:

  # cbsd srcup
  # cbsd srcup ver=head         # for CURRENT (HEAD)
  # cbsd srcup ver=13           # for FreeBSD 13-RELENG (STABLE)
  # cbsd srcup ver=6.0.0        # for DragonflyBSD 6.0, see tags:
                                #   git://git.dragonflybsd.org/dragonfly.git

${H3_COLOR}See also${N0_COLOR}:

 cbsd sources --help
 cbsd bases --help
 cbsd buildworld --help

"
. ${subrdir}/nc.subr

readconf srcup.conf
readconf srcup-${platform}.conf
unset ver arch stable

. ${cbsdinit}

if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
	readconf cbsd_queue.conf
	[ -z "${cbsd_queue_backend}" ] && MOD_CBSD_QUEUE_DISABLED="1"
fi

over="${ver}"
oarch="${arch}"

init_svn()
{
	SCM=""

	if [ -f "/usr/bin/svnlite" ]; then
		SCM="/usr/bin/svnlite"
	elif [ -f "/usr/local/bin/svn" ]; then
		SCM="/usr/local/bin/svn"
	else
		err 1 "${N1_COLOR}No svn in the base. Please install devel/subversion${N0_COLOR}"
	fi

	[ -z "${scmbase}" ] && scmbase="${SVNBASE}"

	if [ "${stable}" = "1" ]; then
		SCM_URL="${scmbase}/stable/${ver}"
	else
		SCM_URL="${scmbase}/releng/${ver}"
	fi

	if [ "${ver}" = "14.0" -o "${ver}" = "14" ]; then
		SCM_URL="${scmbase}/head"
	fi

	return 0
}

init_git()
{
	SCM=

	if [ -f "/usr/local/bin/git" ]; then
		SCM="/usr/local/bin/git"
	else
		err 1 "${N1_COLOR}no git in the base. please install: ${N2_COLOR}pkg install -y devel/git${N0_COLOR}"
	fi

	if [ -z "${scmbase}" ]; then
		[ -z "${GITBASE}" ] && err 1 "${N1_COLOR}empty GITBASE variable. Please specify GITBASE via ${N2_COLOR}srcup.conf${N0_COLOR}"
		scmbase="${GITBASE}"
	fi
	SCM_URL="${scmbase}"

	[ -d "${dst}/.git" ] && return 0

	local CBSDPATH="${PATH}"
	# reset CBSD PATH
	# it is necessary that the calling of any commands via git
	# does not conflict with the same CBSD commands
	export PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"

	set -o xtrace
	cd ${dst} && ${SCM} init
	nice -n 19 ${IDLE_IONICE} ${SCM} remote add origin ${SCM_URL}
	nice -n 19 ${IDLE_IONICE} ${SCM} fetch ${git_flags} origin
	set +o xtrace

	# restore CBSD PATH
	export PATH="${CBSDPATH}"

	return 0
}

svn_checkout()
{
	local _ret=0
	local _srcdir

	_srcdir=$( ${REALPATH_CMD} ${dst} )

	# repair and upgrade
	if [ -d "${_srcdir}/.svn" ]; then
		cd ${_srcdir}
		${ECHO} "${N1_COLOR}Processing svn cleanup, please wait...${N0_COLOR}"
		nice -n 19 ${IDLE_IONICE} ${SCM} cleanup
	fi
	${ECHO} "${N1_COLOR}Processing svn update...${N0_COLOR}"
	[ -z "${rev}" ] && rev="head"
	cbsdlogger NOTICE ${CBSD_APP}: processing svn update: ${SCM} checkout -r ${rev} ${SCM_URL} ${_srcdir}
	echo "${SCM} checkout -r ${rev} ${SCM_URL} ${_srcdir}"
	nice -n 19 ${IDLE_IONICE} ${SCM} checkout -r ${rev} ${SCM_URL} ${_srcdir}
	_ret=$?
}

git_checkout()
{
	local _depth _remotes _origin
	local _ret=0 _p2 _branch

	[ "${depth}" != "0" ] && _depth="${depth}"

	[ -z "${SCM_GIT_BRANCH}" ] && err 1 "${N1_COLOR}empty SCM_GIT_BRANCH${N0_COLOR}"

	${ECHO} "${N1_COLOR}selected branch: ${N2_COLOR}${SCM_GIT_BRANCH}${N0_COLOR}"

	if [ -d "${dst}/.git" ]; then
		echo "cd ${dst} && ${SCM} ${git_flags} branch ${SCM_GIT_BRANCH}"
		cbsdlogger NOTICE ${CBSD_APP}: processing git checkout: ${SCM_GIT_BRANCH} in ${dst}

		local CBSDPATH="${PATH}"
		# reset CBSD PATH
		# it is necessary that the calling of any commands via git
		# does not conflict with the same CBSD commands
		export PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"

		set -o xtrace
		cd ${dst}
		nice -n 19 ${IDLE_IONICE} ${SCM} reset --hard				# reset to source default

		_remotes="remotes/"
		_origin="origin/"

		# remove 'remotes/' + 'origin/'
		_p2=${SCM_GIT_BRANCH##*${_remotes}}
		_branch=${_p2##*${_origin}}

		[ -z "${_branch}" ] && err 1 "${N1_COLOR}${CBSD_APP} error: empty branch var SCM_GIT_BRANCH${N0_COLOR}"
		${ECHO} "${N1_COLOR}${CBSD_APP} swith to branch: ${N2_COLOR}${_branch}${N0_COLOR}"

		nice -n 19 ${IDLE_IONICE} ${SCM} pull ${git_pull_flags}
		_ret=$?

		if [ -n "${rev}" ]; then
			nice -n 19 ${IDLE_IONICE} ${SCM} checkout ${rev}
			_ret=$?
		else
			nice -n 19 ${IDLE_IONICE} ${SCM} checkout ${_branch}
			_ret=$?
		fi
		set +o xtrace
		# restore CBSD PATH
		export PATH="${CBSDPATH}"
	else
		${ECHO} "${N1_COLOR}${CBSD_APP}: clone error: no ${N2_COLOR}.git${N0_COLOR}"
		_ret=1
	fi

	return ${_ret}
}

status_is_maintenance_soft()
{
	cbsdsqlrw local "UPDATE bsdsrc SET status='1' WHERE ver=\"${ver}\""
}

status_is_maintenance_hard()
{
	cbsdsqlrw local "UPDATE bsdsrc SET status='2' WHERE ver=\"${ver}\""

}

status_is_normal()
{
	cbsdsqlrw local "UPDATE bsdsrc SET status='0' WHERE ver=\"${ver}\""
}

cleanup_sources()
{
	local _incomplete=0
	local _rootdir

	[ -f ${LOCKFILE} ] && ${RM_CMD} -f ${LOCKFILE}

	# not SCM dir?
	if [ ! -d ${dst}/.svn -o ! -d ${dst}/.git ]; then
		_incomplete=1
	fi

	# even so Makefile exist?
	if [ -r "${dst}/Makefile" ]; then
		_incomplete=0
	fi

	if [ ${_incomplete} -eq 1 ]; then
		${RM_CMD} -rf ${dst}
		_rootdir=$( ${DIRNAME_CMD} ${dst} )
		unregister_src
		# try to remove empty parent dir
		${RMDIR_CMD} ${_rootdir} || true
		err 1 "No source code for ${ver}"
	fi

	# restore operability status
	status_is_normal
}

### MAIN ###
if [ -z "${ver}" -o "${ver}" = "native" ]; then
	# ver=$( ${SYSCTL_CMD} -n kern.osrelease| ${CUT_CMD} -d - -f 1 )
	# we preffer uname as source, due to some environment have UNAME_r for overwrite version
	tmpver=$( ${UNAME_CMD} -r )
	ver=${tmpver%%-*}
	unset tmpver
fi

# 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}/build.subr
readconf buildworld.conf
. ${subrdir}/universe.subr

init_distcc
init_notify
init_target_arch
init_srcdir
init_supported_arch
init_make_flags

. ${subrdir}/build.subr

if [ -n "${dst}" ]; then
	dst="${srcdir}/src_${ver}/src"
else
	dst="${SRC_DIR}"
fi

${ECHO} "${N1_COLOR}Platform: ${N2_COLOR}${platform}${N0_COLOR}"
LOCKFILE=${ftmpdir}/src_$( ${miscdir}/cbsd_md5 ${dst} ).lock
makelock ${LOCKFILE}

[ ! -d "${dst}" ] && ${MKDIR_CMD} -p ${dst}

trap "cleanup_sources > /dev/null 2>&1" HUP INT ABRT BUS TERM EXIT
. ${subrdir}/time.subr

case "${checkout_method}" in
	svn*)
		st_time=$( ${DATE_CMD} +%s )
		init_svn

		# conditional registration:
		init_scm_and_version
		register_src

		# CBSD QUEUE
		if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
			[ -n "${cbsd_srcup_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_srcup_queue_name} cmd=srcup id=src${ver} platform=${platform} ver=${ver} rev="-" date="-" stable="${stable}" status=1 || true
		fi

		if [ ! -f "${dst}/Makefile" ]; then
			status_is_maintenance_hard
		else
			status_is_maintenance_soft
		fi

		svn_checkout
		init_scm_and_version
		end_time=$( ${DATE_CMD} +%s )
		diff_time=$(( end_time - st_time ))
		diff_time=$( displaytime ${diff_time} )
		${ECHO} "${N1_COLOR}svn_checkout src done ${N2_COLOR}in ${diff_time}${N0_COLOR}"
		cbsdlogger NOTICE ${CBSD_APP}: svn_checkout src done in ${diff_time}. with errcode: ${_ret}
		;;
	git*)
		st_time=$( ${DATE_CMD} +%s )

		init_git
		# conditional registration:
		init_scm_and_version
		register_src

		if [ ! -f "${dst}/Makefile" ]; then
			status_is_maintenance_hard
		else
			status_is_maintenance_soft
		fi

		git_checkout
		init_scm_and_version

		end_time=$( ${DATE_CMD} +%s )
		diff_time=$(( end_time - st_time ))
		diff_time=$( displaytime ${diff_time} )
		${ECHO} "${N1_COLOR}git_checkout src done ${N2_COLOR}in ${diff_time}${N0_COLOR}"
		cbsdlogger NOTICE ${CBSD_APP}: svn_checkout src done in ${diff_time}. with errcode: ${_ret}
		;;
	*)
		err 1 "${ECHO}unknown checkout method, please specify it via: ${N2_COLOR}srcup.conf${N0_COLOR}"
esac

# todo: apply_cbsd_patch should be x11, not sign for global patch
if [ "${apply_cbsd_patch}" = "1" ]; then
	${ECHO} "${N1_COLOR}${CBSD_APP}: apply patch: ${N2_COLOR}apply_cbsd_patch=1${N0_COLOR}"
	/usr/local/bin/cbsd srcpatch $*
elif [ "${apply_cbsd_9p_patch}" = "1" ]; then
	${ECHO} "${N1_COLOR}${CBSD_APP}: apply patch: ${N2_COLOR}apply_cbsd_9p_patch=1${N0_COLOR}"
	/usr/local/bin/cbsd srcpatch $*
elif [ "${apply_cbsd_vesa_fb}" = "1" ]; then
	${ECHO} "${N1_COLOR}${CBSD_APP}: apply patch: ${N2_COLOR}apply_cbsd_vesa_fb=1${N0_COLOR}"
	/usr/local/bin/cbsd srcpatch $*
fi

register_src

# CBSD QUEUE
if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
	[ -n "${cbsd_srcup_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_srcup_queue_name} cmd=update id=src${ver} platform=${platform} ver=${ver} rev="${SCM_REV}" date="${date}" stable="${stable}" status=1 || true
	[ -n "${cbsd_srcup_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_srcup_queue_name} cmd=srcup id=src${ver} status=2 || true
fi

status_is_normal

exit 0
