prvng_core/nulib/lib_provisioning/utils/templates.nu
Jesús Pérez c6ff85c872
refactor(config/cache + utils + config/commands): 7 files selective (ADR-025 L2)
Batch of 7 files, 2 stars each -> selective.

config/cache/commands.nu:
  cache/core.nu     [cache-clear-type get-cache-stats]
  cache/metadata.nu DROPPED (dead)

config/cache/mod.nu:
  cache/core.nu     [get-cache-stats]
  cache/metadata.nu DROPPED (dead)

config/cache/sops.nu:
  cache/core.nu     [cache-clear-type cache-lookup cache-write]
  cache/metadata.nu DROPPED (dead)

config/cache/final.nu:
  cache/core.nu     [cache-clear-type cache-lookup cache-write]
  cache/metadata.nu DROPPED (dead)

utils/templates.nu:
  utils/logging.nu [is-debug-enabled]
  config/accessor  DROPPED (dead)

utils/error.nu:
  utils/logging.nu   [is-debug-enabled is-metadata-enabled]
  utils/interface.nu [_ansi] (kept, already selective; promoted to absolute)
  config/accessor    DROPPED (dead)

config/commands.nu:
  config/encryption.nu [9 symbols]
  config/accessor      DROPPED (dead)

Validation: 5/7 files 0 errors. 2 files (cache/commands, utils/templates)
show pre-existing errors matching baseline. Zero new errors.

Refs: ADR-025
2026-04-17 09:14:43 +01:00

170 lines
7.1 KiB
Text

# Selective imports (ADR-025 Phase 3 Layer 2).
# config/accessor star-import was dead — dropped.
use lib_provisioning/utils/logging.nu [is-debug-enabled]
export def run_from_template [
template_path: string # Template path
vars_path: string # Variable file with settings for template
run_file: string # File to run
out_file?: string # Out file path
--check_mode # Use check mode to review and not create server
--only_make # not run
] {
# Check if nu_plugin_tera is available and load if needed
let tera_available = (plugin list | where name == "tera" | length) > 0
if not $tera_available {
let load_result = (do { plugin use tera } | complete)
if $load_result.exit_code != 0 {
_print $"🛑 (_ansi red)Error(_ansi reset) nu_plugin_tera not available - template rendering not supported"
return false
}
}
if not ( $template_path | path exists ) {
_print $"🛑 (_ansi red)Error(_ansi reset) template ($template_path) (_ansi red)not found(_ansi reset)"
return false
}
if not ( $vars_path | path exists ) {
_print $"🛑 (_ansi red)Error(_ansi reset) vars file ($vars_path) (_ansi red)not found(_ansi reset)"
return false
}
let out_file_name = ($out_file | default "")
# Debug: Show what file we're trying to open
if (is-debug-enabled) {
_print $"🔍 Template vars file: ($vars_path)"
if ($vars_path | path exists) {
_print "📄 File preview (first 3 lines):"
_print (open $vars_path --raw | lines | take 3 | str join "\n")
} else {
_print $"❌ File does not exist!"
}
}
# Load variables from YAML/JSON file
if not ($vars_path | path exists) {
_print $"❌ Variables file not found: ($vars_path)"
return false
}
if (is-debug-enabled) {
_print $"🔍 Parsing YAML configuration: ($vars_path)"
}
# Load vars file
if not ($vars_path | path exists) {
_print $"❌ Vars file does not exist: ($vars_path)"
return false
}
# Render template using tera-render plugin with JSON file path
# The plugin accepts either a record (pipeline) or JSON path (parameter)
# Using JSON path avoids type conversion issues
if not ((plugin list | where name == "tera" | length) > 0) {
_print $"❌ nu_plugin_tera not available"
return false
}
# Ensure tera plugin is loaded in this context
(plugin use tera)
# Call tera-render with context data
if (is-debug-enabled) {
_print $"DEBUG: tera-render ($template_path) with context from ($vars_path)"
_print $"DEBUG: template exists: ($template_path | path exists)"
_print $"DEBUG: vars exists: ($vars_path | path exists)"
}
# Load variables from JSON file
# Variables are saved as JSON (see servers/utils.nu line 169)
if not ($vars_path | path exists) {
_print $"🛑 (_ansi red)Error(_ansi reset) variables file not found: ($vars_path)"
return false
}
_print $"📄 Loading variables from: ($vars_path)"
let raw_content = (open $vars_path --raw)
_print $"📊 File size: ($raw_content | str length) bytes"
# tera-render requires a JSON file path — Nu records with `nothing` values (YAML null)
# cause "Type not supported" when passed as pipeline input to the plugin.
# Convert to a temporary JSON file and pass the path instead.
let json_vars_path = if ($vars_path | str ends-with ".json") {
$vars_path
} else {
let tmp = (mktemp --suffix ".json")
open $vars_path | to json | save -f $tmp
$tmp
}
let result = (tera-render $template_path $json_vars_path)
if not ($vars_path | str ends-with ".json") { rm -f $json_vars_path }
if ($result | describe) == "nothing" or ($result | str length) == 0 {
let text = $"(_ansi yellow)template(_ansi reset): ($template_path)\n(_ansi yellow)vars(_ansi reset): ($vars_path)\n(_ansi red)Failed(_ansi reset)"
print $"(_ansi red)ERROR(_ansi red) nu_plugin_tera render:\n($text)"
exit
}
if not $only_make and (is-debug-enabled) or ($check_mode and ($out_file_name | is-empty)) {
if (is-debug-enabled) and not $check_mode {
_print $"Result running: \n (_ansi default_dimmed)nu_plugin_tera render ($template_path) ($vars_path)(_ansi reset)"
}
let cmd = ((get-file-viewer) | default (if (^bash -c "type -P bat" | is-not-empty) { "bat" } else { "cat" }))
if $cmd != "bat" { _print $"(_ansi magenta_bold)----------------------------------------------------------------------------------------------------------------(_ansi reset)"}
(echo $result | run-external $cmd -)
if $cmd != "bat" { _print $"(_ansi magenta_bold)----------------------------------------------------------------------------------------------------------------(_ansi reset)"}
_print $"Saved in (_ansi green_bold)($run_file)(_ansi reset)"
}
$result | str replace --all "\\ " "\\" | save --append $run_file
if $only_make {
if ($out_file_name | is-not-empty) {
(cat $run_file | tee { save -f $out_file_name } | ignore)
}
return true
}
if $check_mode and not $only_make {
if $out_file_name == "" {
_print $"✅ No errors found !\nTo save command to a file, run next time adding: (_ansi blue)--outfile \(-o\)(_ansi reset) file-path-to-save "
} else {
(cat $run_file | tee { save -f $out_file_name } | ignore)
_print $"✅ No errors found !\nSave in (_ansi green_bold)(_ansi i)($out_file_name)(_ansi reset)"
}
return true
}
if $out_file_name != "" and ($out_file_name | path type) == "file" {
(^bash $run_file | save --force $out_file_name)
} else {
let res = if (is-debug-enabled) {
(^bash -x $run_file | complete)
} else {
(^bash $run_file | complete)
}
if $res.exit_code != 0 {
_print $"\n🛑 (_ansi red)Error(_ansi reset) run from template ($template_path | path basename) (_ansi green_bold)($run_file)(_ansi reset) (_ansi red_bold)failed(_ansi reset) "
_print $"\n($res.stdout)"
return false
}
}
true
}
export def on_template_path [
source_path: string
vars_path: string
remove_path: bool
on_error_exit: bool
] {
for it in (^ls ...(glob $"($source_path)/*")| lines) {
let item = ($it | str trim | str replace -r ':$' '')
if ($item | is-empty) or ($item | path basename | str starts-with "tmp.") or ($item | path basename | str starts-with "_") { continue }
if ($item | path type) == "dir" {
if (ls $item | length) == 0 { continue }
(on_template_path $item $vars_path $remove_path $on_error_exit)
continue
}
if not ($item | str ends-with ".j2") or not ($item | path exists) { continue }
if not (run_from_template $item $vars_path ($item | str replace ".j2" "") --only_make) {
echo $"🛑 Error on_template_path (_ansi red_bold)($item)(_ansi reset) and vars (_ansi yellow_bold)($vars_path)(_ansi reset)"
if $on_error_exit { exit 1 }
}
if $remove_path { rm -f $item }
}
}