#!/usr/bin/env nu # Enhanced Module Loader CLI with Template and Layer Support # Supports the new layered template architecture use ../nulib/taskservs/discover.nu * use ../nulib/taskservs/load.nu * use ../nulib/providers/discover.nu * use ../nulib/providers/load.nu * use ../nulib/clusters/discover.nu * use ../nulib/clusters/load.nu * # Load workspace template utilities source ../../workspace/tools/template-utils.nu source ../../workspace/tools/layer-utils.nu # Main module loader command with enhanced features def main [subcommand?: string] { if ($subcommand | is-empty) { print_enhanced_help return } match $subcommand { "help" => print_enhanced_help "discover" => print_discover_help "load" => print_load_help "list" => print_list_help "unload" => print_unload_help "template" => print_template_help "layer" => print_layer_help "override" => print_override_help _ => { print $"Unknown command: ($subcommand)" print_enhanced_help } } } # === TEMPLATE COMMANDS === # List available templates export def "main template list" [ --type = "all", # Template type: taskservs, providers, servers, clusters, all --format = "table" # Output format: table, yaml, json ] { let manifest = open ../../workspace/registry/manifest.yaml let templates = match $type { "taskservs" => $manifest.templates.taskservs "providers" => $manifest.templates.providers "servers" => $manifest.templates.servers "clusters" => $manifest.templates.clusters "all" => $manifest.templates _ => { error make {msg: $"Invalid type: ($type). Use: taskservs, providers, servers, clusters, all"} } } match $format { "json" => ($templates | to json) "yaml" => ($templates | to yaml) "table" => ($templates | table) _ => ($templates | table) } } # Extract infrastructure patterns to templates export def "main template extract" [ infra_name: string, # Infrastructure to extract from (e.g., "wuji") --to: string = "templates", # Target: templates, workspace --type = "all", # Extract type: taskservs, providers, all --overwrite = false # Overwrite existing templates ] { print $"๐Ÿ”„ Extracting patterns from ($infra_name) infrastructure" let infra_path = $"workspace/infra/($infra_name)" if not ($infra_path | path exists) { error make {msg: $"Infrastructure ($infra_name) not found at ($infra_path)"} } # Extract taskservs if requested if $type in ["taskservs", "all"] { extract_taskserv_patterns $infra_name $to $overwrite } # Extract provider configurations if requested if $type in ["providers", "all"] { extract_provider_patterns $infra_name $to $overwrite } print $"โœ… Extraction completed for ($infra_name)" } # Apply template to infrastructure export def "main template apply" [ template_name: string, # Template to apply (e.g., "kubernetes-ha") target_infra: string, # Target infrastructure name --provider = "upcloud", # Target provider --customize = false # Open for customization after apply ] { print $"๐Ÿ”„ Applying template ($template_name) to ($target_infra)" let manifest = open ../../workspace/registry/manifest.yaml let template_info = get_template_info $manifest $template_name if ($template_info | is-empty) { error make {msg: $"Template ($template_name) not found"} } # Create target directory if it doesn't exist let target_dir = $"workspace/infra/($target_infra)" mkdir $target_dir apply_template_to_infra $template_info $target_infra $provider if $customize { print $"๐Ÿ”ง Opening template for customization..." ^$env.EDITOR $"($target_dir)/taskservs/($template_name).k" } print $"โœ… Template applied successfully to ($target_infra)" } # === LAYER COMMANDS === # Show layer resolution order export def "main layer show" [ --infra?: string # Show resolution for specific infrastructure ] { print "๐Ÿ“‹ Layer Resolution Order:" print "1. Core Layer (Priority: 100) - provisioning/extensions" print "2. Workspace Layer (Priority: 200) - provisioning/workspace/templates" if ($infra | is-not-empty) { print $"3. Infra Layer (Priority: 300) - workspace/infra/($infra)" } else { print "3. Infra Layer (Priority: 300) - workspace/infra/{name}" } let layers = open ../../workspace/layers/core.layer.k | get core_layer let workspace_layer = open ../../workspace/layers/workspace.layer.k | get workspace_layer print "\n๐Ÿ“Š Layer Details:" print $"Core provides: (($layers.provides | str join ', '))" print $"Workspace provides: (($workspace_layer.provides | str join ', '))" } # Test layer resolution for a specific module export def "main layer test" [ module_name: string, # Module to test (e.g., "kubernetes") --infra?: string, # Infrastructure context --provider = "upcloud" # Provider context ] { print $"๐Ÿงช Testing layer resolution for ($module_name)" test_layer_resolution $module_name $infra $provider } # === OVERRIDE COMMANDS === # Create override for existing configuration export def "main override create" [ module_type: string, # Type: taskservs, providers, servers infra_name: string, # Target infrastructure module_name: string, # Module to override --from?: string, # Source template to override from --interactive = false # Interactive override creation ] { print $"๐Ÿ”ง Creating override for ($module_name) in ($infra_name)" let override_dir = $"workspace/infra/($infra_name)/overrides" mkdir $override_dir if ($from | is-not-empty) { copy_template_as_override $from $override_dir $module_name } if $interactive { ^$env.EDITOR $"($override_dir)/($module_name).k" } print $"โœ… Override created for ($module_name)" } # === ENHANCED LOAD COMMANDS === # Enhanced load with layer support export def "main load enhanced" [ type: string, # Module type: taskservs, providers, clusters workspace: string, # Workspace path modules: list, # Module names to load --layer = "workspace", # Layer to load from: core, workspace, templates --force = false, # Force overwrite --with-overrides = false # Apply infrastructure overrides ] { print $"๐Ÿ”„ Loading ($type) from ($layer) layer into: ($workspace)" match $type { "taskservs" => { load_taskservs_with_layer $workspace $modules $layer $force $with_overrides } "providers" => { load_providers_with_layer $workspace $modules $layer $force $with_overrides } "clusters" => { load_clusters_with_layer $workspace $modules $layer $force $with_overrides } _ => { error make {msg: $"Invalid type: ($type). Use: taskservs, providers, clusters"} } } print $"โœ… Enhanced loading completed" } # === HELPER FUNCTIONS === def extract_taskserv_patterns [infra_name: string, target: string, overwrite: bool] { let source_dir = $"workspace/infra/($infra_name)/taskservs" let target_dir = $"provisioning/workspace/templates/taskservs" if ($source_dir | path exists) { print $" ๐Ÿ“ฆ Extracting taskserv patterns..." for file in (ls $source_dir | get name) { let filename = ($file | path basename) let target_file = $"($target_dir)/($filename)" if ($overwrite or not ($target_file | path exists)) { print $" โžœ Extracting ($filename)" cp $file $target_file } else { print $" โš ๏ธ Skipping ($filename) (already exists)" } } } } def extract_provider_patterns [infra_name: string, target: string, overwrite: bool] { let source_dir = $"workspace/infra/($infra_name)/defs" let target_dir = $"provisioning/workspace/templates/providers" if ($source_dir | path exists) { print $" ๐Ÿ“ฆ Extracting provider patterns..." for file in (ls $source_dir | where name =~ "_defaults\.k$" | get name) { let filename = ($file | path basename) let provider_name = ($filename | str replace "_defaults.k" "") let target_file = $"($target_dir)/($provider_name)/defaults.k" mkdir ($"($target_dir)/($provider_name)") if ($overwrite or not ($target_file | path exists)) { print $" โžœ Extracting ($provider_name) defaults" cp $file $target_file } else { print $" โš ๏ธ Skipping ($provider_name) defaults (already exists)" } } } } def get_template_info [manifest: record, template_name: string] -> record { # Search through all template categories let taskserv_templates = $manifest.templates.taskservs | items {|key, value| if $key == $template_name { $value | insert type "taskserv" | insert name $key } else if ($value | describe) == "record" { $value | items {|variant_key, variant_value| if $variant_key == $template_name { $variant_value | insert type "taskserv" | insert name $key | insert variant $variant_key } else { null } } | where {|x| $x != null} | first } else { null } } | where {|x| $x != null} | first $taskserv_templates } def test_layer_resolution [module_name: string, infra: string, provider: string] { print $" Layer 1 (Core): Checking provisioning/extensions/taskservs/($module_name)" let core_exists = ("provisioning/extensions/taskservs" | path join $module_name | path exists) print $" Core layer: ($core_exists)" print $" Layer 2 (Workspace): Checking provisioning/workspace/templates/taskservs/($module_name)" let workspace_exists = ("provisioning/workspace/templates/taskservs" | path join $module_name | path exists) print $" Workspace layer: ($workspace_exists)" if ($infra | is-not-empty) { print $" Layer 3 (Infra): Checking workspace/infra/($infra)/taskservs/($module_name).k" let infra_exists = ("workspace/infra" | path join $infra "taskservs" $"($module_name).k" | path exists) print $" Infra layer: ($infra_exists)" } } # === HELP FUNCTIONS === def print_enhanced_help [] { print "Enhanced Module Loader CLI - Discovery, Templates, and Layers" print "" print "Usage: module-loader-enhanced [options]" print "" print "Commands:" print " discover [query] [--format ] - Discover available modules" print " load - Load modules into workspace" print " load enhanced [--layer ] - Enhanced load with layers" print " list - List loaded modules" print " unload - Unload module from workspace" print "" print "Template Commands:" print " template list [--type ] - List available templates" print " template extract [--to ] - Extract patterns to templates" print " template apply