diff options
Diffstat (limited to 'subr.ex/ex_init.subr')
-rw-r--r-- | subr.ex/ex_init.subr | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/subr.ex/ex_init.subr b/subr.ex/ex_init.subr new file mode 100644 index 00000000..5dc4f857 --- /dev/null +++ b/subr.ex/ex_init.subr @@ -0,0 +1,449 @@ +# +# Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 LucĂa Andrea Illanes Albornoz <lucia@luciaillanes.de> +# set +o errexit -o noglob -o nounset is assumed. +# + +exp_setrstatus() { + local _epsrs_rstatus="${1#\$}" _epsrs_status="${2}"; + eval ${_epsrs_rstatus}=\"${_epsrs_status}\"; + return 0; +}; + +# +# ex_init_env() - initialise build environment +# @_rstatus: out reference to variable of status string on failure +# @_rhname: out reference to variable of build hostname +# @_ruser: out reference to variable of build user +# @_name_base: base name for messages and theme file(s) +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_env() { + local _eie_rstatus="${1#\$}" _eie_rhname="${2#\$}" _eie_ruser="${3#\$}" \ + _eie_name_base="${4}" \ + _eie_fname="" _eie_lang="${LANG:-C}" _eie_lang_="" _eie_name="" \ + _eie_rc=0; + _eie_lang="${_eie_lang%%_*}"; + + if ! cd "${0%/*}"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to change working directory to \`'"${0%/*}"''\''.'; + elif ! umask 022; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to set umask(2).'; + elif ! eval ${_eie_rhname}=\"\$\(hostname\)\"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to obtain hostname.'; + elif ! eval ${_eie_ruser}=\"\$\(id -nu\)\"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to obtain username.'; + else + for _eie_fname in \ + $(find subr.ex -name *.subr) \ + $(find subr.pkg -name *.subr) \ + $(find subr.rtl -name *.subr) \ + "etc/${_eie_name_base}.theme" \ + ; + do + if ! . "${_eie_fname}"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to source \`'"${_eie_fname}"''\''.'; + break; + fi; + done; + + if [ "${_eie_rc}" -eq 0 ]; then + if [ -e "${_eie_name_base}.local" ]; then + if ! . "${_eie_name_base}.local"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to source \`'"${_eie_name_base}"'.local'\''.'; + fi; + fi; + fi; + + if [ "${_eie_rc}" -eq 0 ]; then + for _eie_name in ${_eie_name_base} rtl; do + for _eie_lang_ in ${_eie_lang} C; do + _eie_fname="etc/${_eie_name}.msgs.${_eie_lang_}"; + if [ -e "${_eie_fname}" ]; then + if ! . "${_eie_fname}"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to source \`'"${_eie_fname}"''\''.'; + break; + fi; + + if [ -e "${_eie_fname}.local" ]; then + if ! . "${_eie_fname}.local"; then + _eie_rc=1; + exp_setrstatus "${_eie_rstatus}" 'failed to source \`'"${_eie_fname}"'.local'\''.'; + fi; + fi; + break; + fi; + done; + + if [ "${_eie_rc}" -ne 0 ]; then + break; + fi; + done; + fi; + fi; + export LANG=C LC_ALL=C; + + return "${_eie_rc}"; +}; + +# +# ex_init_getopts() - process command-line arguments +# @_rstatus: out reference to variable of status string on failure +# @_fn: reference to function called to process command-line argument +# @_optstring: getopts(1) optstring +# @...: command-line arguments as "${@}" +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_getopts() { + local _eig_rstatus="${1#\$}" _eig_fn="${2}" _eig_optstring="${3}" \ + _eig_arg="" _eig_fn_rc=0 _eig_opt="" _eig_shiftfl=0 \ + OPTARG="" OPTIND=0; + shift 3; + + if ! "${_eig_fn}" init "${_eig_rstatus}"; then + return 1; + fi; + + while [ "${#}" -gt 0 ]; do + case "${1}" in + --*) + "${_eig_fn}" longopt "${_eig_rstatus}" "${1}" ${2:-}; + _eig_fn_rc="${?}"; + + case "${_eig_fn_rc}" in + 0) ;; + 1) return 1; ;; + + *) shift "$((${_eig_fn_rc} - 1))"; + continue; ;; + esac; + ;; + esac; + + OPTIND=0; + if getopts "${_eig_optstring}" _eig_opt; then + "${_eig_fn}" opt "${_eig_rstatus}" "${_eig_opt}" "${OPTARG:-}" "${@}"; + _eig_fn_rc="${?}"; + + case "${_eig_fn_rc}" in + 0) ;; + 1) return 1; ;; + + *) shift "$((${_eig_fn_rc} - 1))"; + continue; ;; + esac; + else + "${_eig_fn}" nonopt "${_eig_rstatus}" "${@}"; + _eig_fn_rc="${?}"; + + case "${_eig_fn_rc}" in + 0) ;; + 1) return 1; ;; + + *) shift "$((${_eig_fn_rc} - 1))"; + continue; ;; + esac; + fi; + done; + + if ! "${_eig_fn}" done "${_eig_rstatus}"; then + return 1; + fi; + + return 0; +}; + +# +# ex_init_help() - display usage screen and exit if requested in command-line arguments +# @_rstatus: out reference to variable of status string on failure +# @_args_long: optional list of long (prefixed with `--') arguments +# @_name_base: base name for usage screen file +# @_optstring: getopts(1) optstring +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_help() { + local _eih_rstatus="${1#\$}" _eih_args_long="${2}" \ + _eih_name_base="${3}" _eih_optstring="${4}" \ + _eih_arg_long="" _eih_opt="" _eih_shiftfl=0 \ + OPTIND; + shift 4; + + while [ "${#}" -gt 0 ]; do + case "${1}" in + -h) + if [ -t 1 ]; then + cat "etc/${_eih_name_base}.usage.short"; + else + sed 's/\[[0-9]\+m//g' "etc/${_eih_name_base}.usage.short"; + fi; + exit 0; + ;; + + --help) + if [ -t 1 ]; then + cat "etc/${_eih_name_base}.usage"; + else + sed 's/\[[0-9]\+m//g' "etc/${_eih_name_base}.usage"; + fi; + exit 0; + ;; + + *=*) shift; continue; + ;; + + *) _eih_shiftfl=0; + for _eih_arg_long in ${_eih_args_long}; do + if [ "${_eih_arg_long}" = "${1}" ]; then + _eih_shiftfl=1; + fi; + done; + if [ "${_eih_shiftfl}" = 1 ]; then + shift; continue; + fi; + ;; + esac; + + OPTIND=0; + if getopts "${_eih_optstring}" _eih_opt 2>/dev/null; then + case "${_eih_opt}" in + h) + if [ -t 1 ]; then + cat "etc/${_eih_name_base}.usage.short"; + else + sed 's/\[[0-9]\+m//g' "etc/${_eih_name_base}.usage.short"; + fi; + exit 0; + ;; + esac; + shift $((${OPTIND}-1)); OPTIND=1; + else + shift; + fi; + done; + + return 0; +}; + +# +# ex_init_files() - initialise build files +# @_rstatus: out reference to variable of status string on failure +# @_rclean_builds: in reference to variable of -C argument value +# @_rdist: in reference to variable of -D argument value +# @_build_log_fname: absolute pathname to build log file +# @_build_log_last_fname: absolute pathname to last build log file +# @_build_status_in_progress_fname: absolute pathname to build-in-progress status file +# @_check_path_vars: list of pathname variables to check +# @_clear_env_vars_except: list of environment variables to not unset when clearing the environment +# @_clear_prefix_paths: list of directory pathnames to clear in the top-level prefix +# @_rpm_semaphore: absolute pathname to rpmbuild(1) parallel jobs count semaphore +# @_dlcachedir: absolute pathname to download cache directory +# @_prefix: absolute pathname to top-level prefix +# @_prefix_rpm: absolute pathname to RPM files prefix +# @_workdir: absolute pathname to build-specific temporary directory +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_files() { + local _eif_rstatus="${1#\$}" _eif_rclean_builds="${2#\$}" _eif_rdist="${3#\$}" \ + _eif_build_log_fname="${4}" _eif_build_log_last_fname="${5}" \ + _eif_build_status_in_progress_fname="${6}" _eif_check_path_vars="${7}" \ + _eif_clear_env_vars_except="${8}" _eif_clear_prefix_paths="${9}" \ + _eif_rpm_semaphore="${10}" _eif_dlcachedir="${11}" _eif_prefix="${12}" \ + _eif_prefix_rpm="${13}" _eif_workdir="${14}" \ + _eif_log_last_fname="" _eif_log_last_num=1 _eif_rc=0; + + if ! rtl_fileop mkdir "${_eif_dlcachedir}" "${_eif_workdir}"\ + || rtl_lmatch "${_eif_rdist}" "rpm" ","\ + && ! rtl_fileop mkdir "${_eif_prefix_rpm}"; then + _eif_rc=1; + rtl_setrstatus "${_eif_rstatus}" 'cannot create build directories.'; + elif [ -e "${_eif_build_status_in_progress_fname}" ]; then + _eif_rc=1; + rtl_setrstatus "${_eif_rstatus}" 'another build targeting this architecture and build type is currently in progress.'; + elif ! rtl_clean_env "${_eif_clear_env_vars_except}"; then + _eif_rc=1; + rtl_setrstatus "${_eif_rstatus}" 'failed to clean environment.'; + elif ! rtl_check_path_vars "${_eif_rstatus}" "${_eif_check_path_vars}"; then + _eif_rc=1; + else + export LC_ALL="${LC_ALL:-C}"; + export TMP="${_eif_workdir}" TMPDIR="${_eif_workdir}"; + touch "${_eif_build_status_in_progress_fname}"; + + if [ -e "${_eif_build_log_fname}" ]; then + while [ -e "${_eif_build_log_fname}.${_eif_log_last_num}" ]; do + : $((_eif_log_last_num+=1)); + done; + + _eif_log_last_fname="${_eif_build_log_fname}.${_eif_log_last_num}"; + rtl_fileop mv "${_eif_build_log_fname}" "${_eif_log_last_fname}"; + rtl_fileop ln_symbolic "${_eif_log_last_fname}" "${_eif_build_log_last_fname}"; + fi; + + rtl_fileop touch "${_eif_build_log_fname}"; + rtl_log_set_fname "${_eif_build_log_fname}"; + + rtl_fileop rm "${_eif_rpm_semaphore}"; + + if rtl_lmatch "${_eif_rclean_builds}" $"prefix" ","; then + trap "rm -f \"${_eif_build_status_in_progress_fname}\" 2>/dev/null; + + rtl_log_msgV \"fatalexit\" \"${MSG_build_aborted}\"" HUP INT TERM USR1 USR2; + rtl_log_msgV "info" "${MSG_build_clean_prefix}"; + + for _eif_pname in ${_eif_clear_prefix_paths}; do + if ! rtl_fileop rm "${_eif_prefix}/${_eif_pname}"; then + _eif_rc=1; + rtl_setrstatus "${_eif_rstatus}" 'failed to remove \`'"${_eif_prefix:+${_eif_prefix}/}${_eif_pname}'"'.'; + break; + fi; + done; + + trap - HUP INT TERM USR1 USR2; + fi; + + export PATH="${_eif_prefix}/localcross/bin${PATH:+:${PATH}}"; + export PATH="${_eif_prefix}/bin${PATH:+:${PATH}}"; + fi; + + return "${_eif_rc}"; +}; + +# +# ex_init_logging() - initialise build logging +# @_rstatus: out reference to variable of status string on failure +# @_rverbose_tags: in reference to out variable of -V argument value +# @_verbose: -[vV] argument value +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_logging() { + local _eil_rstatus="${1#\$}" _eil_rverbose_tags="${2#\$}" _eil_verbose="${3}" \ + _eil_tag="" _eil_tags="" _eil_tags_enable="" _eil_rc=0; + + rtl_log_clear_tags; + case "${_eil_verbose}" in + + 0) if eval [ \"\${#${_eil_rverbose_tags}}\" -eq 0 ]; then + rtl_log_enable_tagsV "${LOG_TAGS_normal}"; + fi; + ;; + + 1) rtl_log_enable_tagsV "${LOG_TAGS_verbose}"; ;; + + *) _eil_rc=1; + rtl_setrstatus "${_eil_rstatus}" 'invalid verbosity level (max. -v)'; + ;; + + esac; + + if [ "${_eil_rc}" -eq 0 ]; then + eval _eil_tags="\${${_eil_rverbose_tags}}"; + case "${_eil_tags}" in + + +*) rtl_log_enable_tagsV "${LOG_TAGS_normal}"; + eval ${_eil_rverbose_tags}="\${${_eil_rverbose_tags}#+}"; + ;; + + *) ;; + + esac; + + rtl_llift2 "${_eil_rverbose_tags}" \$_eil_tags "," " "; + + for _eil_tag in ${_eil_tags}; do + case "${_eil_tag}" in + + all) rtl_log_enable_tagsV "${LOG_TAGS_all}"; ;; + + clear|none) rtl_log_clear_tags; ;; + + normal) rtl_log_enable_tagsV "${LOG_TAGS_normal}"; ;; + + verbose) rtl_log_enable_tagsV "${LOG_TAGS_verbose}"; ;; + + *) rtl_lsearch_patternl2 \$LOG_TAGS_all \$_eil_tags_enable "${_eil_tag}" ","; + if [ "${#_eil_tags_enable}" -gt 0 ]; then + rtl_log_enable_tagsV "${_eil_tags_enable}"; + else + _eil_rc=1; + rtl_setrstatus "${_eil_rstatus}" 'invalid log tag or tag pattern \`'"${_eil_tag}"''\''.'; + break; + fi; + ;; + + esac; + done; + fi; + + return "${_eil_rc}"; +}; + +# +# ex_init_prereqs() - initialise build prerequisite commands +# @_rstatus: out reference to variable of status string on failure +# @_prereqs: list of prerequisite commands +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_prereqs() { + local _eip_rstatus="${1#\$}" _eip_prereqs="${2}" \ + _eip_rc=0; + + if ! rtl_check_prereqsV "${_eip_rstatus}" ${_eip_prereqs}; then + _eip_rc=1; + elif ! awk -V 2>/dev/null | grep -q "^GNU Awk "; then + _eip_rc=1; + rtl_setrstatus "${_eip_rstatus}" 'awk(1) in \$PATH must be GNU Awk.'; + elif ! (FNAME="$(mktemp)" && { trap "rm -f \"\${FNAME}\"" EXIT HUP INT TERM USR1 USR2; \ + sed -i'' -e '' "${FNAME}" >/dev/null 2>&1; }); + then + _eip_rc=1; + rtl_setrstatus "${_eip_rstatus}" 'sed(1) in \${PATH} does not support the \`-i'\'' option.'; + fi; + + return "${_eip_rc}"; +}; + +# +# ex_init_theme() - initialise theme +# @_rstatus: out reference to variable of status string on failure +# @_hname: build hostname +# @_name_base: base name for theme file(s) +# @_theme: theme name +# +# Returns: zero (0) on success, non-zero (>0) on failure +# +ex_init_theme() { + local _eit_rstatus="${1#\$}" _eit_hname="${2}" _eit_name_base="${3}" _eit_theme="${4}" \ + _eit_rc=0 _eit_theme_fname=""; + + if [ "${_eit_theme:+1}" = 1 ]; then + _eit_theme_fname="etc/${_eit_name_base}.${_eit_theme}.theme"; + else + _eit_theme_fname="etc/${_eit_name_base}.theme.host.${_eit_hname}"; + if ! [ -e "${_eit_theme_fname}" ]; then + _eit_theme_fname="etc/${_eit_name_base}.theme"; + fi; + fi; + + if ! [ -e "${_eit_theme_fname}" ]; then + _eit_rc=1; + exp_setrstatus "${_eit_rstatus}" 'failed to source \`'"${_eit_theme_fname}"''\''.'; + else + . "${_eit_theme_fname}"; + fi; + + return "${_eit_rc}"; +}; + +# vim:filetype=sh textwidth=0 |