summaryrefslogtreecommitdiff
path: root/core/modules/loop.sh
blob: 3f7cb0da1afcdef51a9108cd88fb16ee49bb98ee (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
#!/usr/bin/env bash
# Module: loop
# Description: Ejecuta un módulo sobre una lista o matriz de valores
# Author: Luis GuLo
# Version: 0.3.0
# Dependencies: echo, tee

loop_task() {
  local host="$1"; shift
  declare -A args
  local items_raw="" secondary_raw="" target_module=""
  local fail_fast="true"
  declare -A module_args

  # 🌐 Cargar traducciones
  local lang="${shflow_vars[language]:-es}"
  local trfile="$(dirname "${BASH_SOURCE[0]}")/loop.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
      items) items_raw="$value" ;;
      secondary) secondary_raw="$value" ;;
      module) target_module="$value" ;;
      fail_fast) fail_fast="$value" ;;
      *) module_args["$key"]="$value" ;;
    esac
  done

  if [[ -z "$items_raw" || -z "$target_module" ]]; then
    echo "${tr[missing_args]:-❌ [loop] Faltan argumentos obligatorios: items=... module=...}"
    return 1
  fi

  IFS=',' read -r -a items <<< "$items_raw"
  IFS=',' read -r -a secondary <<< "$secondary_raw"

  for item in "${items[@]}"; do
    if [[ "$item" == *:* ]]; then
      item_key="${item%%:*}"
      item_value="${item#*:}"
    else
      item_key="$item"
      item_value=""
    fi

    if [[ -n "$secondary_raw" ]]; then
      for sec in "${secondary[@]}"; do
        run_module "$host" "$target_module" "$item" "$item_key" "$item_value" "$sec" module_args || {
          echo "$(render_msg "${tr[fail_secondary]}" "item=$item" "secondary=$sec")"
          [[ "$fail_fast" == "true" ]] && return 1
        }
      done
    else
      run_module "$host" "$target_module" "$item" "$item_key" "$item_value" "" module_args || {
        echo "$(render_msg "${tr[fail_item]}" "item=$item")"
        [[ "$fail_fast" == "true" ]] && return 1
      }
    fi
  done
}

run_module() {
  local host="$1"
  local module="$2"
  local item="$3"
  local item_key="$4"
  local item_value="$5"
  local secondary_item="$6"
  declare -n args_ref="$7"

  local call_args=()
  for key in "${!args_ref[@]}"; do
    value="${args_ref[$key]}"
    value="${value//\{\{item\}\}/$item}"
    value="${value//\{\{item_key\}\}/$item_key}"
    value="${value//\{\{item_value\}\}/$item_value}"
    value="${value//\{\{secondary_item\}\}/$secondary_item}"
    call_args+=("$key=$value")
  done

  echo "🔁 [loop] → $module con item='$item' secondary='$secondary_item'"

  local PROJECT_ROOT="${SHFLOW_HOME:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
  local MODULE_PATH=""
  local SEARCH_PATHS=("$PROJECT_ROOT/core/modules" "$PROJECT_ROOT/user_modules" "$PROJECT_ROOT/community_modules")
  for search_dir in "${SEARCH_PATHS[@]}"; do
    while IFS= read -r -d '' candidate; do
      [[ "$(basename "$candidate")" == "${module}.sh" ]] && MODULE_PATH="$candidate" && break 2
    done < <(find "$search_dir" -type f -name "${module}.sh" -print0)
  done

  if [[ -z "$MODULE_PATH" ]]; then
    echo "$(render_msg "${tr[module_not_found]}" "module=$module")"
    return 1
  fi

  source "$MODULE_PATH"
  ! declare -f "${module}_task" > /dev/null && echo "$(render_msg "${tr[task_not_found]}" "module=$module")" && return 1

  "${module}_task" "$host" "${call_args[@]}"
}

check_dependencies_loop() {
  local lang="${shflow_vars[language]:-es}"
  local trfile="$(dirname "${BASH_SOURCE[0]}")/loop.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 echo tee; 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]:-✅ [loop] Dependencias disponibles.}"
  return 0
}