首次提交
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
|
||||
if ! type "include" > /dev/null 2>&1; then
|
||||
include() {
|
||||
. "$(cd "$(dirname "$1")" && pwd)/${2}";
|
||||
};
|
||||
fi
|
||||
include "${BASH_SOURCE[0]}" ../pragma_once.bash
|
||||
if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi
|
||||
include "${BASH_SOURCE[0]}" ./global_rely/export.bash
|
||||
include "${BASH_SOURCE[0]}" ./other.bash
|
||||
# shellcheck source=./global_rely/export.bash
|
||||
# shellcheck source=./other.bash
|
||||
|
||||
|
||||
|
||||
# =========================
|
||||
# template.bash
|
||||
# 纯 Bash 模板渲染
|
||||
# 占位符格式: {{KEY}}
|
||||
# =========================
|
||||
|
||||
# 判断某个 key 是否合法
|
||||
_template_validate_key() {
|
||||
local key="$1"
|
||||
[[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]
|
||||
}
|
||||
|
||||
# 转义 replacement,避免 sed 替换时特殊字符出问题
|
||||
_template_escape_replacement() {
|
||||
local s="$1"
|
||||
s="${s//\\/\\\\}"
|
||||
s="${s//&/\\&}"
|
||||
s="${s//|/\\|}"
|
||||
printf '%s' "$s"
|
||||
}
|
||||
|
||||
# 核心:对一个字符串做渲染
|
||||
# 用法:
|
||||
# template_render_string "hello {{NAME}}" NAME "wyc" AGE "18"
|
||||
template_render_string() {
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "template_render_string: missing template string" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local template_str="$1"
|
||||
shift
|
||||
|
||||
if [ $(( $# % 2 )) -ne 0 ]; then
|
||||
echo "template_render_string: key/value arguments must be paired" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local rendered="$template_str"
|
||||
local key=""
|
||||
local value=""
|
||||
local escaped_value=""
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
key="$1"
|
||||
value="$2"
|
||||
shift 2
|
||||
|
||||
if ! _template_validate_key "$key"; then
|
||||
echo "template_render_string: invalid key: $key" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
escaped_value="$(_template_escape_replacement "$value")"
|
||||
rendered="$(printf '%s' "$rendered" | sed "s|{{${key}}}|${escaped_value}|g")"
|
||||
done
|
||||
|
||||
printf '%s' "$rendered"
|
||||
}
|
||||
|
||||
# 从模板文件渲染到 stdout
|
||||
# 用法:
|
||||
# template_render_file /tmp/a.tpl NAME "wyc" AGE "18"
|
||||
template_render_file() {
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "template_render_file: missing template file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local template_file="$1"
|
||||
shift
|
||||
|
||||
if [ ! -f "$template_file" ]; then
|
||||
echo "template_render_file: template file not found: $template_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local content=""
|
||||
content="$(cat "$template_file")" || return 1
|
||||
template_render_string "$content" "$@"
|
||||
}
|
||||
|
||||
# 从模板文件渲染到目标文件
|
||||
# 用法:
|
||||
# template_render_to_file /tmp/a.tpl /tmp/out.conf NAME "wyc"
|
||||
template_render_to_file() {
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "template_render_to_file: usage: template_render_to_file <template> <output> [KEY VALUE ...]" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local template_file="$1"
|
||||
local output_file="$2"
|
||||
shift 2
|
||||
|
||||
local output_dir=""
|
||||
output_dir="$(dirname "$output_file")"
|
||||
|
||||
mkdir -p "$output_dir" || return 1
|
||||
|
||||
template_render_file "$template_file" "$@" > "$output_file" || return 1
|
||||
}
|
||||
|
||||
# 检查模板里还有哪些未替换占位符
|
||||
# 输出唯一 key 列表
|
||||
# 用法:
|
||||
# template_list_placeholders /tmp/a.tpl
|
||||
template_list_placeholders() {
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "template_list_placeholders: usage: template_list_placeholders <template_file>" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local template_file="$1"
|
||||
|
||||
if [ ! -f "$template_file" ]; then
|
||||
echo "template_list_placeholders: template file not found: $template_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
grep -o '{{[A-Za-z_][A-Za-z0-9_]*}}' "$template_file" \
|
||||
| sed 's/^{{//; s/}}$//' \
|
||||
| sort -u
|
||||
}
|
||||
|
||||
# 模板文件示例
|
||||
# server_name={{SERVER_NAME}}
|
||||
# server_port={{SERVER_PORT}}
|
||||
# build_type={{BUILD_TYPE}}
|
||||
# install_prefix={{INSTALL_PREFIX}}
|
||||
|
||||
# 调用方式
|
||||
|
||||
# template_render_to_file_strict \
|
||||
# /ae/bash/demo/app.conf.tpl \
|
||||
# /ae/bash/demo/out/app.conf \
|
||||
# SERVER_NAME "demo-server" \
|
||||
# SERVER_PORT "8080" \
|
||||
# BUILD_TYPE "Release" \
|
||||
# INSTALL_PREFIX "/opt/demo"
|
||||
|
||||
# 严格模式:如果还有未替换占位符则报错
|
||||
# 用法:
|
||||
# template_render_to_file_strict /tmp/a.tpl /tmp/out.conf NAME "wyc"
|
||||
template_render_to_file_strict() {
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "template_render_to_file_strict: usage: template_render_to_file_strict <template> <output> [KEY VALUE ...]" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local template_file="$1"
|
||||
local output_file="$2"
|
||||
shift 2
|
||||
check_file_var template_file
|
||||
template_render_to_file "$template_file" "$output_file" "$@" || return 1
|
||||
|
||||
if grep -q '{{[A-Za-z_][A-Za-z0-9_]*}}' "$output_file"; then
|
||||
echo "template_render_to_file_strict: unresolved placeholders found in: $output_file" >&2
|
||||
grep -o '{{[A-Za-z_][A-Za-z0-9_]*}}' "$output_file" | sort -u >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# declare -A tpl_vars
|
||||
# tpl_vars[SERVER_NAME]="demo-server"
|
||||
# tpl_vars[SERVER_PORT]="8080"
|
||||
# tpl_vars[BUILD_TYPE]="Debug"
|
||||
# tpl_vars[INSTALL_PREFIX]="/opt/demo"
|
||||
#
|
||||
# template_render_file_by_assoc \
|
||||
# /ae/bash/demo/app.conf.tpl \
|
||||
# tpl_vars \
|
||||
# > /ae/bash/demo/out/app.conf
|
||||
|
||||
template_render_file_by_assoc() {
|
||||
if [ $# -ne 2 ]; then
|
||||
echo "template_render_file_by_assoc: usage: template_render_file_by_assoc <template_file> <assoc_name>" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local template_file="$1"
|
||||
local assoc_name="$2"
|
||||
|
||||
check_file_var template_file
|
||||
|
||||
if [ ! -f "$template_file" ]; then
|
||||
echo "template_render_file_by_assoc: template file not found: $template_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local content=""
|
||||
content="$(cat "$template_file")" || return 1
|
||||
|
||||
local key=""
|
||||
local value=""
|
||||
local escaped_value=""
|
||||
|
||||
local rendered="$content"
|
||||
local -n kv_ref="$assoc_name"
|
||||
|
||||
for key in "${!kv_ref[@]}"; do
|
||||
if ! _template_validate_key "$key"; then
|
||||
echo "template_render_file_by_assoc: invalid key: $key" >&2
|
||||
return 1
|
||||
fi
|
||||
value="${kv_ref[$key]}"
|
||||
escaped_value="$(_template_escape_replacement "$value")"
|
||||
rendered="$(printf '%s' "$rendered" | sed "s|{{${key}}}|${escaped_value}|g")"
|
||||
done
|
||||
|
||||
printf '%s' "$rendered"
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user