Blob Blame History Raw
#
# set +o errexit -o noglob is assumed.
#

#
# exp_pkg_dispatch_complete() - XXX
# @_dispatch_fn:	top-level dispatch function name
# @_group_names:	build group name(s)
# @_pkg_disabled:	list of disabled packages
# @_pkg_finished:	list of finished packages
#
# Return:		zero (0) on success, non-zero (>0) on failure.
#
exp_pkg_dispatch_complete() {
	local _dispatch_fn="${1}" _group_name="${2}" _pkg_disabled="${3}" _pkg_finished="${4}" _pkg_name="";
	for _pkg_name in ${_pkg_disabled}; do
		"${_dispatch_fn}" disabled_pkg "${_group_name}" "${_pkg_name}";
	done;
	for _pkg_name in ${_pkg_finished}; do
		"${_dispatch_fn}" skipped_pkg "${_group_name}" "${_pkg_name}";
	done;
};

#
# exp_pkg_dispatch_group() - dispatch a single build group
# @_build_steps_default:	list of default build steps
# @_build_vars_default:		list of default build variables
# @_dispatch_fn:		top-level dispatch function name
# @_group_name:			build group name
# @_njobs_max:			maximum count of simultaneous jobs
# @_pipe_path:			pathname to build FIFO
# @_restart_at:			optional comma-separated list of build steps at which to rebuild or ALL
# @_restart_recursive:		optional flag specifiying either no dependency expansion (0,) dependency expansion (1,) dependency expansion and forcibly rebuild (2.)
# @_workdir:			pathname to build-specific temporary directory
#
# Return:			zero (0) on success, non-zero (>0) on failure.
#
exp_pkg_dispatch_group() {
	local	_build_steps_default="${1}" _build_vars_default="${2}" _dispatch_fn="${3}"	\
		_group_name="${4}" _njobs_max="${5}" _pipe_path="${6}" _restart_at="${7}"	\
		_restart_recursive="${8}" _workdir="${9}" _pipe_msg="" _pkg_name="" _rc=0;
	rtl_fileop mkfifo "${_pipe_path}";
	while true; do
		while [ "${EXP_PKG_DISPATCH_NJOBS:-0}" -gt 0 ] && read _pipe_msg; do
		case "${_pipe_msg%% *}" in
		done)	: $((EXP_PKG_DISPATCH_NJOBS-=1)); _pkg_name="${_pipe_msg#done * }";
			"${_dispatch_fn}" finish_pkg ${_pipe_msg#done };
			EXP_PKG_COMPLETE="$(rtl_lconcat "${EXP_PKG_COMPLETE}" "${_pkg_name}")";
			EXP_PKG_NAMES="$(rtl_lfilter "${EXP_PKG_NAMES}" "${_pkg_name}")";
			EX_PKG_DISPATCH_WAIT="$(rtl_lfilter "${EX_PKG_DISPATCH_WAIT}" "${_pkg_name}")";
			if [ -n "${EXP_PKG_NAMES}" ] && [ "${_rc}" -eq 0 ]; then
				if [ "${EXP_PKG_DISPATCH_NJOBS}" -ne "${_njobs_max}" ]; then
					exp_pkg_dispatch_packages "${_build_steps_default}"	\
						"${_build_vars_default}" "${_dispatch_fn}"	\
						"${_group_name}" "${_njobs_max}"		\
						"${_pipe_path}" "${EXP_PKG_COMPLETE}"		\
						"${_restart_at}" "${_restart_recursive}" "${_workdir}";
				fi;
			elif [ "${EXP_PKG_DISPATCH_NJOBS:-0}" -eq 0 ]; then
				break;
			fi; ;;
		fail)	: $((EXP_PKG_DISPATCH_NJOBS-=1)); _rc=1;
			"${_dispatch_fn}" fail_pkg ${_pipe_msg#fail }; ;;
		msg_pkg)
			"${_dispatch_fn}" msg_pkg ${_pipe_msg#msg_pkg }; ;;
		step)	"${_dispatch_fn}" step_pkg ${_pipe_msg#step }; ;;
		esac; done <>"${_pipe_path}";
		if [ -n "${EXP_PKG_NAMES}" ] && [ "${_rc}" -eq 0 ]; then
			if [ "${EXP_PKG_DISPATCH_NJOBS}" -ne "${_njobs_max}" ]; then
				exp_pkg_dispatch_packages "${_build_steps_default}"		\
					"${_build_vars_default}" "${_dispatch_fn}"		\
					"${_group_name}" "${_njobs_max}" "${_pipe_path}"	\
					"${EXP_PKG_COMPLETE}" "${_restart_at}"			\
					"${_restart_recursive}" "${_workdir}";
			fi;
		elif [ "${EXP_PKG_DISPATCH_NJOBS:-0}" -eq 0 ]; then
			break;
		fi;
	done;
	rtl_fileop rm "${_pipe_path}";
	return "${_rc}";
};

#
# exp_pkg_dispatch_package() - dispatch single named packages
# @_build_steps_default:	list of default build steps
# @_build_vars_default:		list of default build variables
# @_dispatch_fn:		top-level dispatch function name
# @_group_name:			build group name
# @_pkg_name:			single package name
# @_restart_at:			optional comma-separated list of build steps at which to rebuild or ALL
# @_workdir:			pathname to build-specific temporary directory
#
# Return:			zero (0) on success, non-zero (>0) on failure, ${EXP_PKG_DISPATCH_NJOBS}, ${EXP_PKG_DISPATCH_COUNT}, ${EXP_PKG_NAMES}, and ${EX_PKG_DISPATCH_WAIT} may be mutated post-return.
#
exp_pkg_dispatch_package() {
	local	_build_steps_default="${1}" _build_vars_default="${2}" _dispatch_fn="${3}"	\
		_group_name="${4}" _pkg_name="${5}" _restart_at="${6}" _workdir="${7}";
	if "${_dispatch_fn}" start_pkg "${_group_name}" "${_pkg_name}" "$((${EXP_PKG_DISPATCH_COUNT}+1))" "${EXP_PKG_DISPATCH_COUNT_MAX}"; then
		: $((EXP_PKG_DISPATCH_NJOBS+=1)); : $((EXP_PKG_DISPATCH_COUNT+=1)); EX_PKG_DISPATCH_WAIT="$(rtl_lconcat "${EX_PKG_DISPATCH_WAIT}" "${_pkg_name}")";
		(set +o errexit -o noglob; BUILD_IS_PARENT=0;
		if ex_pkg_env "${_build_steps_default}" "${_build_vars_default}"		\
				"${_group_name}" "${_pkg_name}" "${_restart_at}" "${_workdir}"; then
			ex_pkg_exec "${_dispatch_fn}" "${_group_name}" "${_pkg_name}" "${_restart_at}";
		else
			return 1;
		fi;) 1>"${_workdir}/${_pkg_name}_stderrout.log" 2>&1 3>"${_pipe_path}" &
	else
		return 1;
	fi;
};

#
# exp_pkg_dispatch_packages() - dispatch set of packages
# @_build_steps_default:	list of default build steps
# @_build_vars_default:		list of default build variables
# @_dispatch_fn:		top-level dispatch function name
# @_group_name:			build group name
# @_njobs_max:			maximum count of simultaneous jobs
# @_pipe_path:			pathname to parent-child process FIFO
# @_pkg_complete:		list of completed packages
# @_restart_at:			optional comma-separated list of build steps at which to rebuild or ALL
# @_restart_recursive:		optional flag specifiying either no dependency expansion (0,) dependency expansion (1,) dependency expansion and forcibly rebuild (2.)
# @_workdir:			pathname to build-specific temporary directory
#
# Return:			zero (0) on success, non-zero (>0) on failure, ${EXP_PKG_DISPATCH_NJOBS}, ${EXP_PKG_DISPATCH_COUNT}, ${EXP_PKG_NAMES}, and ${EX_PKG_DISPATCH_WAIT} may be mutated post-return.
#
exp_pkg_dispatch_packages() {
	local	_build_steps_default="${1}" _build_vars_default="${2}" _dispatch_fn="${3}"		\
		_group_name="${4}" _njobs_max="${5}" _pipe_path="${6}" _pkg_complete="${7}"		\
		_restart_at="${8}" _restart_recursive="${9}" _workdir="${10}"				\
		_njob=0 _pkg_depends="" _pkg_name="";
	for _njob in $(seq 1 $((${_njobs_max}-${EXP_PKG_DISPATCH_NJOBS}))); do
		for _pkg_name in ${EXP_PKG_NAMES}; do
			if ! rtl_lmatch "${_pkg_complete}" "${_pkg_name}"\
			&& ! rtl_lmatch "${EX_PKG_DISPATCH_WAIT}" "${_pkg_name}"\
			&& ex_pkg_check_depends "${_pkg_complete}" "${_pkg_name}" "${EX_PKG_DISPATCH_WAIT}" "${_restart_recursive}"; then
				exp_pkg_dispatch_package "${_build_steps_default}"			\
					"${_build_vars_default}" "${_dispatch_fn}"			\
					"${_group_name}" "${_pkg_name}" "${_restart_at}"		\
					"${_workdir}"; break;
			fi;
		done;
	done;
};

#
# ex_pkg_dispatch() - dispatch a set of build group
# @_build_steps_default:	list of default build steps
# @_build_vars_default:		list of default build variables
# @_dispatch_fn:		top-level dispatch function name
# @_group_names:		build group name(s)
# @_njobs_max:			maximum count of simultaneous jobs
# @_pipe_path:			pathname to build FIFO
# @_restart:			optional comma-separated list of package names to rebuild
# @_restart_at:			optional comma-separated list of build steps at which to rebuild or ALL
# @_restart_recursive:		optional flag specifiying either no dependency expansion (0,) dependency expansion (1,) dependency expansion and forcibly rebuild (2.)
# @_workdir:			pathname to build-specific temporary directory
#
# Return:			zero (0) on success, non-zero (>0) on failure, ${EX_PKG_DISPATCH_UNKNOWN} and ${EX_PKG_DISPATCH_WAIT} mutated post-return.
#
ex_pkg_dispatch() {
	local	_build_steps_default="${1}" _build_vars_default="${2}" _dispatch_fn="${3}"		\
		_group_names="${4}" _njobs_max="${5}" _pipe_path="${6}" _restart="${7}"			\
		_restart_at="${8}" _restart_recursive="${9}" _workdir="${10}"				\
		_pkg_name="" _pkg_names="" _rc=0							\
		EXP_PKG_COMPLETE EXP_PKG_DISABLED EXP_PKG_FINISHED EXP_PKG_DISPATCH_COUNT		\
		EXP_PKG_DISPATCH_COUNT_MAX EXP_PKG_DISPATCH_NJOBS EXP_PKG_NAMES;
	EX_PKG_DISPATCH_UNKNOWN=""; EX_PKG_DISPATCH_WAIT="";
	for _group_name in $(rtl_uniq $(rtl_lunfold_depends '${_name}_GROUP_DEPENDS' ${_group_names})); do
		EXP_PKG_COMPLETE="" EXP_PKG_DISABLED="" EXP_PKG_FINISHED="";
		EXP_PKG_DISPATCH_COUNT=0 EXP_PKG_DISPATCH_COUNT_MAX=0 EXP_PKG_DISPATCH_NJOBS=0;
		EXP_PKG_NAMES="" EX_PKG_DISPATCH_WAIT="";
		if "${_dispatch_fn}" start_group "${_group_name}" ""; then
			if rtl_fileop mkdir "${_workdir}"\
			&& rtl_log_msg vnfo "Resolving \`${_group_name}' dependencies..."\
			&& ex_pkg_expand_packages "${_group_name}" "${_restart}" "${_restart_recursive}"\
			&& exp_pkg_dispatch_complete "${_dispatch_fn}" "${_group_name}" "${EXP_PKG_DISABLED}" "${EXP_PKG_FINISHED}"\
			&& rtl_log_msg vnfo "Resolved \`${_group_name}' dependencies."\
			&& EXP_PKG_DISPATCH_COUNT_MAX="$(rtl_llength "${EXP_PKG_NAMES}")"\
			&& [ "${EXP_PKG_DISPATCH_COUNT_MAX}" -gt 0 ]; then
				_pkg_names="$(rtl_lconcat "${_pkg_names}" "${EXP_PKG_NAMES}")";
				exp_pkg_dispatch_group "${_build_steps_default}"			\
					"${_build_vars_default}" "${_dispatch_fn}" "${_group_name}"	\
					"${_njobs_max}" "${_pipe_path}" "${_restart_at}"		\
					"${_restart_recursive}" "${_workdir}"; _rc="${?}";
			fi;
			"${_dispatch_fn}" finish_group "${_group_name}" "";
			if [ "${_rc}" -ne 0 ]; then
				break;
			fi;
		fi;
	done;
	if ! rtl_lmatch "${_restart}" "ALL LAST"; then
		for _pkg_name in ${_restart}; do
			if ! rtl_lmatch "${_pkg_names}" "${_restart}"; then
				EX_PKG_DISPATCH_UNKNOWN="$(rtl_lconcat "${EX_PKG_DISPATCH_UNKNOWN}" "${_pkg_name}")";
			fi;
		done;
	fi;
	if [ -n "${EX_PKG_DISPATCH_UNKNOWN}" ]; then
		_rc=1;
	fi;
	return "${_rc}";
};

# vim:filetype=sh textwidth=0