blob: 887a47bfb8f3813e6108815dd16d40a4272094d5 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#!/usr/bin/env bash
# Module: template
# Description: Genera archivos a partir de plantillas con variables {{var}}, bucles, includes y delimitadores configurables
# Author: Luis GuLo
# Version: 0.4.0
# Dependencies: bash, sed, tee, grep, cat
# 🧭 Detección de raíz del proyecto
PROJECT_ROOT="${SHFLOW_HOME:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
TEMPLATE_DIR="$PROJECT_ROOT/core/templates"
template_task() {
local host="$1"; shift
declare -A args
local start_delim="{{" end_delim="}}" strict="false"
declare -A vars
# 🌐 Cargar traducciones
local lang="${shflow_vars[language]:-es}"
local trfile="$(dirname "${BASH_SOURCE[0]}")/template.tr.${lang}"
declare -A tr
if [[ -f "$trfile" ]]; then
while IFS='=' read -r k v; do tr["$k"]="$v"; done < "$trfile"
fi
# Parsear argumentos
for arg in "$@"; do
key="${arg%%=*}"
value="${arg#*=}"
case "$key" in
src) src="$value" ;;
dest) dest="$value" ;;
become) become="$value" ;;
delimiters)
start_delim="${value%% *}"
end_delim="${value#* }"
;;
strict) strict="$value" ;;
*) vars["$key"]="$value" ;;
esac
done
local prefix=""
[ "$become" = "true" ] && prefix="sudo"
local template_path="$TEMPLATE_DIR/$src"
[[ ! -f "$template_path" ]] && echo "$(render_msg "${tr[missing_template]}" "path=$template_path")" && return 1
local rendered=""
local line loop_active="false" loop_key="" loop_buffer=()
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" =~ ${start_delim}[[:space:]]*include[[:space:]]*\"([^\"]+)\"[[:space:]]*${end_delim} ]]; then
include_file="${BASH_REMATCH[1]}"
include_path="$TEMPLATE_DIR/$include_file"
[[ -f "$include_path" ]] && rendered+=$(cat "$include_path")$'\n'
continue
fi
if [[ "$line" =~ ^#LOOP[[:space:]]+([a-zA-Z0-9_]+)$ ]]; then
loop_active="true"
loop_key="${BASH_REMATCH[1]}"
loop_buffer=()
continue
fi
if [[ "$line" == "#ENDLOOP" ]]; then
loop_active="false"
IFS=',' read -r -a items <<< "${vars[$loop_key]}"
for item in "${items[@]}"; do
for loop_line in "${loop_buffer[@]}"; do
rendered+=$(replace_vars "$loop_line" "$item" "$start_delim" "$end_delim")$'\n'
done
done
continue
fi
if [[ "$loop_active" == "true" ]]; then
loop_buffer+=("$line")
continue
fi
rendered+=$(replace_vars "$line" "" "$start_delim" "$end_delim")$'\n'
done < "$template_path"
if [[ "$strict" == "true" ]]; then
missing=$(echo "$rendered" | grep -o "${start_delim}[^${end_delim}]*${end_delim}" | sort -u)
if [[ -n "$missing" ]]; then
echo "${tr[missing_vars]:-❌ [template] Variables no definidas:}"
echo "$missing"
return 1
fi
fi
echo "$rendered" | $prefix tee "$dest" > /dev/null
echo "$(render_msg "${tr[generated]}" "dest=$dest")"
}
replace_vars() {
local line="$1"
local item="$2"
local start_delim="$3"
local end_delim="$4"
for key in "${!vars[@]}"; do
line="${line//${start_delim}${key}${end_delim}/${vars[$key]}}"
done
[[ -n "$item" ]] && line="${line//${start_delim}item${end_delim}/$item}"
echo "$line"
}
check_dependencies_template() {
local lang="${shflow_vars[language]:-es}"
local trfile="$(dirname "${BASH_SOURCE[0]}")/template.tr.${lang}"
declare -A tr
if [[ -f "$trfile" ]]; then
while IFS='=' read -r k v; do tr["$k"]="$v"; done < "$trfile"
fi
local missing=()
for cmd in sed tee grep cat; do
command -v "$cmd" >/dev/null 2>&1 || missing+=("$cmd")
done
if [[ ${#missing[@]} -gt 0 ]]; then
echo "$(render_msg "${tr[missing_deps]}" "cmds=${missing[*]}")"
return 1
fi
echo "${tr[deps_ok]:-✅ [template] Todas las dependencias están disponibles}"
return 0
}
|