#!/bin/sh volume_root='/run/angie' tmp_dir="${volume_root}/tmp" merged_root="${volume_root}/merged" target_root="${volume_root}" have_envvar() { [ -n "$1" ] || return 1 grep -Ezq "^$1=" /proc/self/environ || return } ## unexporting variable in (POSIX) sh is PITA =/ unexport() { unset ___k ___v for ___k ; do [ -n "${___k}" ] || continue have_envvar "${___k}" || continue ___v=$(eval printf '%s' "\"\${${___k}}\"") eval "unset ${___k}" eval "${___k}=$(env printf '%s' \"\${___v}\")" unset ___v done unset ___k } ## likely the same as in https://pkg.go.dev/strconv#ParseBool gobool_to_int() { ## local value=$1 ## local default=$2 case "${1:-_}" in 1 | [Tt] | [Tt][Rr][Uu][Ee] ) echo 1 ;; 0 | [Ff] | [Ff][Aa][Ll][Ss][Ee] ) echo 0 ;; * ) echo "${2:-error}" ;; esac } [ -n "${__IEP_SRC:-}" ] || __IEP_SRC="$0" IEP_TRACE=$(gobool_to_int "${IEP_TRACE:-0}" 0) export IEP_TRACE if [ "${IEP_TRACE}" = 1 ] ; then log_always() { echo "# $(date +'%Y-%m-%d %H:%M:%S.%03N %z'): ${__IEP_SRC}${*:+: $*}" >&2 ; } else log_always() { echo "# ${__IEP_SRC}${*:+: $*}" >&2 ; } fi IEP_VERBOSE=$(gobool_to_int "${IEP_VERBOSE:-${IEP_TRACE}}" "${IEP_TRACE}") export IEP_VERBOSE if [ "${IEP_VERBOSE}" = 1 ] ; then log() { log_always "$@" ; } else log() { : ;} fi log_file() { sed -E '/^./s,^, ,' < "$1" >&2 ; } if [ "${IEP_VERBOSE}" = 0 ] ; then ln_s() { ln -s "$@" || return; } cp_a() { cp -a "$@" || return; } else ln_s() { ln -sv "$@" || return; } cp_a() { cp -av "$@" || return; } fi ln_cp() { if [ -h "$1" ] ; then ln_s "$(readlink -e "$1")" "$2" else cp_a "$1" "$2" fi } have_cmd() { command -v "$1" >/dev/null 2>&1 || return ; } strip_suffix() { printf '%s' "${1%"$2"}" | tr -s '/' ; } untemplate_path() { case "$1" in ## inplace "${volume_root}"/* | /etc/angie/run/* ) strip_suffix "$1" "$2" ;; /etc/angie/conf.d/* | /etc/angie/mod.d/* | /etc/angie/modules.d/* | /etc/angie/njs.d/* | /etc/angie/site.d/* | /etc/angie/snip.d/* ) strip_suffix "$1" "$2" ;; /etc/angie/static.d/* ) strip_suffix "$1" "$2" ;; ## set appropriate location /etc/angie/* ) strip_suffix "${volume_root}${1#/etc/angie}" "$2" ;; /tmp/* ) log_always "untemplate_path() shouldn't work with /tmp/: $1" strip_suffix "$1" "$2" ;; ## last resort - STRONGLY AVOID /* ) log_always "untemplate_path() does uncommon/last-resort mapping for: $1" strip_suffix "${tmp_dir}$1" "$2" ;; ## misbehavior! * ) log_always "untemplate_path() doesn't work with relative paths: $1" return 1 ;; esac } install_userdir() { if [ "${IEP_ROOT}" = 1 ] ; then install -d -o "${NGX_USER}" -g "${NGX_GROUP}" "$@" else install -d "$@" fi } untemplate_file_envsubst() { [ -n "$1" ] || return [ -f "$1" ] || { log_always "file not found: $1" ; return 1 ; } [ -n "${NGX_ENVSUBST_SUFFIX:-}" ] || { log "NGX_ENVSUBST_SUFFIX is empty" ; return 1 ; } __dest="$2" [ -n "${__dest}" ] || __dest=$(untemplate_path "$1" "${NGX_ENVSUBST_SUFFIX}") || return if [ -e "${__dest}" ] ; then log "untemplate_file_envsubst: destination file already exists" return fi [ -d "${__dest%/*}" ] || install_userdir "${__dest%/*}" || return log "Running envsubst: $1 -> ${__dest}" envsubst.sh < "$1" > "${__dest}" || return } ## notes: ## - (OPTIONAL) place own wrapper script as "/usr/local/sbin/jinja.py" ## in order to perform different template processing untemplate_file_jinja() { [ -n "$1" ] || return [ -f "$1" ] || { log_always "file not found: $1" ; return 1 ; } [ -n "${NGX_JINJA_SUFFIX:-}" ] || { log "NGX_JINJA_SUFFIX is empty" ; return 1 ; } __dest="$2" [ -n "${__dest}" ] || __dest=$(untemplate_path "$1" "${NGX_JINJA_SUFFIX}") || return if [ -e "${__dest}" ] ; then log "untemplate_file_jinja: destination file already exists" return fi [ -d "${__dest%/*}" ] || install_userdir "${__dest%/*}" || return log "Running jinja.py: $1 -> ${__dest}" jinja.py "$1" "${__dest}" || return } untemplate_dir_envsubst() { [ -n "${NGX_ENVSUBST_SUFFIX:-}" ] || { log "NGX_ENVSUBST_SUFFIX is empty" ; return 1 ; } __template_list=$(mktemp) || return find "$@" -follow -type f -name "*${NGX_ENVSUBST_SUFFIX}" \ | sort -uV > "${__template_list}" __have_args="${ENVSUBST_ARGS:+1}" if [ -z "${__have_args}" ] ; then ## optimize envsubst.sh invocation by caching argument list ## ref: envsubst.sh ENVSUBST_ARGS=$(mktemp) || return envsubst-args.sh > "${ENVSUBST_ARGS}" export ENVSUBST_ARGS fi while read -r __orig_file ; do [ -n "${__orig_file}" ] || continue untemplate_file_envsubst "${__orig_file}" done < "${__template_list}" unset __orig_file if [ -z "${__have_args}" ] ; then rm -f "${ENVSUBST_ARGS}" ; unset ENVSUBST_ARGS fi unset __have_args rm -f "${__template_list}" ; unset __template_list } untemplate_dir_jinja() { [ -n "${NGX_JINJA_SUFFIX:-}" ] || { log "NGX_JINJA_SUFFIX is empty" ; return 1 ; } __template_list=$(mktemp) || return find "$@" -follow -type f -name "*${NGX_JINJA_SUFFIX}" \ | sort -uV > "${__template_list}" while read -r __orig_file ; do [ -n "${__orig_file}" ] || continue untemplate_file_jinja "${__orig_file}" done < "${__template_list}" unset __orig_file rm -f "${__template_list}" ; unset __template_list } remap_path() { [ -n "$1" ] || return case "$1" in ## conf /etc/angie/conf.dist/* ) echo "${2:-/etc/angie/conf.d}${1#/etc/angie/conf.dist}" ;; /etc/angie/conf/* ) echo "${2:-/etc/angie/conf.d}${1#/etc/angie/conf}" ;; /angie/conf/* ) echo "${2:-/etc/angie/conf.d}${1#/angie/conf}" ;; ## mod /etc/angie/mod.dist/* ) echo "${2:-/etc/angie/mod.d}${1#/etc/angie/mod.dist}" ;; /etc/angie/mod/* ) echo "${2:-/etc/angie/mod.d}${1#/etc/angie/mod}" ;; /angie/mod/* ) echo "${2:-/etc/angie/mod.d}${1#/angie/mod}" ;; ## modules /etc/angie/modules.dist/* ) echo "${2:-/etc/angie/modules.d}${1#/etc/angie/modules.dist}" ;; /etc/angie/modules/* ) echo "${2:-/etc/angie/modules.d}${1#/etc/angie/modules}" ;; /angie/modules/* ) echo "${2:-/etc/angie/modules.d}${1#/angie/modules}" ;; ## njs /etc/angie/njs.dist/* ) echo "${2:-/etc/angie/njs.d}${1#/etc/angie/njs.dist}" ;; /etc/angie/njs/* ) echo "${2:-/etc/angie/njs.d}${1#/etc/angie/njs}" ;; /angie/njs/* ) echo "${2:-/etc/angie/njs.d}${1#/angie/njs}" ;; ## site /etc/angie/site.dist/* ) echo "${2:-/etc/angie/site.d}${1#/etc/angie/site.dist}" ;; /etc/angie/site/* ) echo "${2:-/etc/angie/site.d}${1#/etc/angie/site}" ;; /angie/site/* ) echo "${2:-/etc/angie/site.d}${1#/angie/site}" ;; ## snip /etc/angie/snip.dist/* ) echo "${2:-/etc/angie/snip.d}${1#/etc/angie/snip.dist}" ;; /etc/angie/snip/* ) echo "${2:-/etc/angie/snip.d}${1#/etc/angie/snip}" ;; /angie/snip/* ) echo "${2:-/etc/angie/snip.d}${1#/angie/snip}" ;; ## static /etc/angie/static.dist/* ) echo "${2:-/etc/angie/static.d}${1#/etc/angie/static.dist}" ;; /etc/angie/static/* ) echo "${2:-/etc/angie/static.d}${1#/etc/angie/static}" ;; /angie/static/* ) echo "${2:-/etc/angie/static.d}${1#/angie/static}" ;; ## log /etc/angie/log.dist/* ) echo "${2:-/etc/angie/log.d}${1#/etc/angie/log.dist}" ;; /angie/log/* ) echo "${2:-/etc/angie/log.d}${1#/angie/log}" ;; ## misbehavior! * ) log_always "remap_path() doesn't know how to handle this path: $1" return 1 ;; esac } combine_remap_path() { [ -n "$1" ] || return case "$1" in "${merged_root}"/* ) echo "${2:-${target_root}}${1#"${merged_root}"}" ;; ## misbehavior! * ) log_always "combine_remap_path() doesn't know how to handle this path: $1" return 1 ;; esac } is_builtin_module() { [ -n "${1:-}" ] || return 1 [ -n "${2:-}" ] || return 1 [ -f "/etc/angie/builtin.$1" ] || return 1 [ -s "/etc/angie/builtin.$1" ] || return 1 grep -Fxq -e "$2" "/etc/angie/builtin.$1" || return 1 } sort_dedup_list() { [ -n "$1" ] || return 0 printf '%s' "$1" \ | tr -s '[:space:]' '\n' | sort -uV | paste -sd ' ' \ | sed -zE 's/^\s+//;s/\s+$//' }