535 lines
17 KiB
Text
535 lines
17 KiB
Text
# Cache Management CLI Commands
|
|
# Provides user-facing commands for cache operations and configuration
|
|
# Follows Nushell 0.109.0+ guidelines
|
|
|
|
# Selective imports (ADR-025 Phase 3 Layer 2).
|
|
# cache/metadata star-import was dead — dropped.
|
|
use domain/cache/core.nu [cache-clear-type get-cache-stats]
|
|
# Avoid importing all modules - use only what's needed
|
|
# use ./config_manager.nu *
|
|
# use ./nickel.nu *
|
|
# use ./sops.nu *
|
|
# use ./final.nu *
|
|
|
|
# ============================================================================
|
|
# Data Operations: Clear, List, Warm, Validate
|
|
# ============================================================================
|
|
|
|
# Clear all or specific type of cache
|
|
export def cache-clear [
|
|
--type: string = "all" # "all", "nickel", "sops", "final", "provider", "platform"
|
|
--force = false # Skip confirmation
|
|
] {
|
|
if (not $force) and ($type == "all") {
|
|
let response = (input "Clear ALL cache? This cannot be undone. (yes/no): ")
|
|
if $response != "yes" {
|
|
print "Cancelled."
|
|
return
|
|
}
|
|
}
|
|
|
|
match $type {
|
|
"all" => {
|
|
print "Clearing all caches..."
|
|
do {
|
|
cache-clear-type "nickel"
|
|
cache-clear-type "sops"
|
|
cache-clear-type "final"
|
|
cache-clear-type "provider"
|
|
cache-clear-type "platform"
|
|
} | complete | ignore
|
|
print "✅ All caches cleared"
|
|
},
|
|
"nickel" => {
|
|
print "Clearing Nickel compilation cache..."
|
|
clear-nickel-cache
|
|
print "✅ Nickel cache cleared"
|
|
},
|
|
"sops" => {
|
|
print "Clearing SOPS decryption cache..."
|
|
clear-sops-cache
|
|
print "✅ SOPS cache cleared"
|
|
},
|
|
"final" => {
|
|
print "Clearing final configuration cache..."
|
|
clear-final-cache
|
|
print "✅ Final config cache cleared"
|
|
},
|
|
_ => {
|
|
print $"❌ Unknown cache type: ($type)"
|
|
}
|
|
}
|
|
}
|
|
|
|
# List cache entries
|
|
export def cache-list [
|
|
--type: string = "*" # "nickel", "sops", "final", etc or "*" for all
|
|
--format: string = "table" # "table", "json", "yaml"
|
|
] {
|
|
let stats = (get-cache-stats)
|
|
|
|
if ($stats.total_entries | is-empty) or ($stats.total_entries == 0) {
|
|
print "📭 Cache is empty"
|
|
return
|
|
}
|
|
|
|
let home = ($env.HOME? | default "~" | path expand)
|
|
let base = ($home | path join ".provisioning" "cache" "config")
|
|
|
|
mut entries = []
|
|
|
|
let type_dir = match $type {
|
|
"all" => $base,
|
|
"nickel" => ($base | path join "nickel"),
|
|
"sops" => ($base | path join "sops"),
|
|
"final" => ($base | path join "workspaces"),
|
|
_ => ($base | path join $type)
|
|
}
|
|
|
|
if not ($type_dir | path exists) {
|
|
print $"No cache directory for type: ($type)"
|
|
return
|
|
}
|
|
|
|
for meta_file in (glob $"($type_dir)/**/*.meta") {
|
|
let cache_file = ($meta_file | str substring 0..-6)
|
|
let meta = (do { open $meta_file } | complete | get stdout)
|
|
|
|
if $meta.exit_code == 0 {
|
|
let size_result = (do {
|
|
if ($cache_file | path exists) {
|
|
$cache_file | stat | get size
|
|
} else {
|
|
0
|
|
}
|
|
} | complete)
|
|
|
|
if $size_result.exit_code == 0 {
|
|
let size_kb = ($size_result.stdout / 1024)
|
|
let cache_type = ($meta_file | path dirname | path basename)
|
|
|
|
$entries = ($entries | append {
|
|
type: $cache_type,
|
|
key: ($cache_file | path basename),
|
|
size_kb: ($size_kb | math round -p 2),
|
|
created: ($meta.stdout.created_at? | default "unknown"),
|
|
expires: ($meta.stdout.expires_at? | default "unknown")
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($entries | length) == 0 {
|
|
print "📭 No cache entries found"
|
|
return
|
|
}
|
|
|
|
match $format {
|
|
"json" => {
|
|
$entries | to json --indent 2 | print
|
|
},
|
|
"yaml" => {
|
|
$entries | to yaml | print
|
|
},
|
|
_ => {
|
|
print $"📦 Cache Entries (($entries | length)) total):\n"
|
|
$entries | table
|
|
}
|
|
}
|
|
}
|
|
|
|
# Warm cache (pre-populate)
|
|
export def cache-warm [
|
|
--workspace: string = ""
|
|
--environment: string = "*"
|
|
] {
|
|
print "🔥 Warming cache..."
|
|
|
|
if ($workspace | is-empty) {
|
|
# Try to get active workspace
|
|
use ../../user/config.nu get-active-workspace
|
|
let active = (get-active-workspace)
|
|
|
|
if ($active | is-empty) {
|
|
print "❌ No active workspace. Use: provisioning workspace activate <name>"
|
|
return
|
|
}
|
|
|
|
print $"Warming cache for workspace: ($active.name)"
|
|
do {
|
|
warm-nickel-cache $active.path
|
|
} | complete | ignore
|
|
} else {
|
|
print $"Warming cache for workspace: ($workspace)"
|
|
}
|
|
|
|
print "✅ Cache warming complete"
|
|
}
|
|
|
|
# Validate cache integrity
|
|
export def cache-validate [] {
|
|
print "🔍 Validating cache integrity..."
|
|
|
|
let home = ($env.HOME? | default "~" | path expand)
|
|
let base = ($home | path join ".provisioning" "cache" "config")
|
|
|
|
if not ($base | path exists) {
|
|
return {
|
|
valid: true,
|
|
total_files: 0,
|
|
errors: [],
|
|
warnings: []
|
|
}
|
|
}
|
|
|
|
mut errors = []
|
|
mut warnings = []
|
|
mut total_files = 0
|
|
|
|
# Check SOPS permissions
|
|
let sops_stats = (get-sops-cache-stats)
|
|
if ($sops_stats.permission_errors | default 0) > 0 {
|
|
$errors = ($errors | append $"SOPS cache: ($sops_stats.permission_errors) files with invalid permissions")
|
|
}
|
|
|
|
# Check all metadata files
|
|
for meta_file in (glob $"($base)/**/*.meta") {
|
|
$total_files += 1
|
|
let cache_file = ($meta_file | str substring 0..-6)
|
|
|
|
let meta_result = (do { open $meta_file } | complete)
|
|
if $meta_result.exit_code != 0 {
|
|
$errors = ($errors | append $"Cannot read metadata: ($meta_file)")
|
|
continue
|
|
}
|
|
|
|
let meta = $meta_result.stdout
|
|
|
|
# Check expiration
|
|
let now = (date now | format date "%Y-%m-%dT%H:%M:%SZ")
|
|
if $now > $meta.expires_at {
|
|
$warnings = ($warnings | append $"Expired cache: ($cache_file)")
|
|
}
|
|
}
|
|
|
|
let result = {
|
|
valid: ($errors | length) == 0,
|
|
total_files: $total_files,
|
|
errors: $errors,
|
|
warnings: $warnings
|
|
}
|
|
|
|
if $result.valid {
|
|
print "✅ Cache validation passed"
|
|
} else {
|
|
print "❌ Cache validation failed"
|
|
for error in $errors {
|
|
print $" ❌ ($error)"
|
|
}
|
|
}
|
|
|
|
if ($warnings | length) > 0 {
|
|
for warning in $warnings {
|
|
print $" ⚠️ ($warning)"
|
|
}
|
|
}
|
|
|
|
$result
|
|
}
|
|
|
|
# ============================================================================
|
|
# Configuration Commands: Show, Get, Set, Reset
|
|
# ============================================================================
|
|
|
|
# Show cache configuration (enhanced with paths and all settings)
|
|
export def cache-config-show [
|
|
--format: string = "table"
|
|
] {
|
|
let config = (get-cache-config)
|
|
|
|
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
print "📋 Cache Configuration"
|
|
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
print ""
|
|
|
|
print "▸ Core Settings:"
|
|
print $" Enabled: ($config.enabled)"
|
|
print $" Max Size: ($config.max_cache_size / 1048576 | math round -p 0) MB"
|
|
print ""
|
|
|
|
print "▸ Cache Location:"
|
|
print $" Base Path: ($config.paths.base)"
|
|
print ""
|
|
|
|
print "▸ Time-To-Live (TTL) Settings:"
|
|
print $" Final Config: ($config.ttl.final_config)s (5 minutes)"
|
|
print $" Nickel Compilation: ($config.ttl.nickel_compilation)s (30 minutes)"
|
|
print $" SOPS Decryption: ($config.ttl.sops_decryption)s (15 minutes)"
|
|
print $" Provider Config: ($config.ttl.provider_config)s (10 minutes)"
|
|
print $" Platform Config: ($config.ttl.platform_config)s (10 minutes)"
|
|
print ""
|
|
|
|
print "▸ Security Settings:"
|
|
print $" SOPS File Permissions: ($config.security.sops_file_permissions)"
|
|
print $" SOPS Dir Permissions: ($config.security.sops_dir_permissions)"
|
|
print ""
|
|
|
|
print "▸ Validation Settings:"
|
|
print $" Strict mtime Checking: ($config.validation.strict_mtime)"
|
|
print ""
|
|
|
|
print "▸ Metadata:"
|
|
print $" Last Modified: ($config.metadata.last_modified)"
|
|
print $" Modified By: ($config.metadata.modified_by)"
|
|
print $" Config Version: ($config.metadata.version)"
|
|
print ""
|
|
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
}
|
|
|
|
# Get specific cache configuration setting
|
|
export def cache-config-get [
|
|
setting_path: string # "enabled", "ttl.final_config", etc.
|
|
] {
|
|
let value = (cache-config-get $setting_path)
|
|
|
|
if ($value | is-empty) {
|
|
print $"Setting not found: ($setting_path)"
|
|
return
|
|
}
|
|
|
|
print $"($setting_path): ($value)"
|
|
$value
|
|
}
|
|
|
|
# Set cache configuration
|
|
export def cache-config-set [
|
|
setting_path: string
|
|
value: any
|
|
] {
|
|
print $"Setting ($setting_path) = ($value)"
|
|
cache-config-set $setting_path $value
|
|
print "✅ Configuration updated"
|
|
}
|
|
|
|
# Reset cache configuration
|
|
export def cache-config-reset [
|
|
setting_path?: string = ""
|
|
] {
|
|
if ($setting_path | is-empty) {
|
|
let confirm = (input "Reset ALL cache configuration to defaults? (yes/no): ")
|
|
if $confirm != "yes" {
|
|
print "Cancelled."
|
|
return
|
|
}
|
|
cache-config-reset
|
|
print "✅ All configuration reset to defaults"
|
|
} else {
|
|
print $"Resetting ($setting_path) to default..."
|
|
cache-config-reset $setting_path
|
|
print "✅ Setting reset to default"
|
|
}
|
|
}
|
|
|
|
# Validate cache configuration
|
|
export def cache-config-validate [] {
|
|
print "Validating cache configuration..."
|
|
let result = (cache-config-validate)
|
|
|
|
if $result.valid {
|
|
print "✅ Configuration is valid"
|
|
} else {
|
|
print "❌ Configuration has errors:"
|
|
for error in $result.errors {
|
|
print $" ❌ ($error)"
|
|
}
|
|
}
|
|
|
|
if ($result.warnings | length) > 0 {
|
|
print "⚠️ Warnings:"
|
|
for warning in $result.warnings {
|
|
print $" ⚠️ ($warning)"
|
|
}
|
|
}
|
|
|
|
$result
|
|
}
|
|
|
|
# ============================================================================
|
|
# Monitoring: Status, Stats
|
|
# ============================================================================
|
|
|
|
# Show comprehensive cache status (configuration + statistics)
|
|
export def cache-status [] {
|
|
let status = (get-cache-status)
|
|
|
|
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
print "📊 Cache Configuration"
|
|
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
let config = $status.configuration
|
|
print $" Enabled: ($config.enabled)"
|
|
print $" Max Size: ($status.max_size_mb) MB"
|
|
print $" Current Usage: ($status.current_usage_percent)%"
|
|
|
|
print ""
|
|
print " TTL Settings:"
|
|
print $" Final Config: ($config.ttl.final_config)s (5 min)"
|
|
print $" Nickel Compilation: ($config.ttl.nickel_compilation)s (30 min)"
|
|
print $" SOPS Decryption: ($config.ttl.sops_decryption)s (15 min)"
|
|
print $" Provider Config: ($config.ttl.provider_config)s (10 min)"
|
|
print $" Platform Config: ($config.ttl.platform_config)s (10 min)"
|
|
|
|
print ""
|
|
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
print "📈 Cache Statistics"
|
|
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
let stats = $status.statistics
|
|
print $" Total Entries: ($stats.total_entries)"
|
|
print $" Total Size: ($stats.total_size_mb | math round -p 2) MB"
|
|
|
|
print ""
|
|
print " By Type:"
|
|
|
|
let nickel_stats = (get-nickel-cache-stats)
|
|
print $" Nickel: ($nickel_stats.total_entries) entries, ($nickel_stats.total_size_mb | math round -p 2) MB"
|
|
|
|
let sops_stats = (get-sops-cache-stats)
|
|
print $" SOPS: ($sops_stats.total_entries) entries, ($sops_stats.total_size_mb | math round -p 2) MB"
|
|
|
|
let final_stats = (get-final-cache-stats)
|
|
print $" Final Config: ($final_stats.total_entries) entries, ($final_stats.total_size_mb | math round -p 2) MB"
|
|
|
|
print ""
|
|
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
}
|
|
|
|
# Show cache statistics only
|
|
export def cache-stats [
|
|
--format: string = "table"
|
|
] {
|
|
let stats = (get-cache-stats)
|
|
|
|
print $"📊 Cache Statistics\n"
|
|
print $" Total Entries: ($stats.total_entries)"
|
|
print $" Total Size: ($stats.total_size_mb | math round -p 2) MB"
|
|
print ""
|
|
|
|
let nickel_stats = (get-nickel-cache-stats)
|
|
let sops_stats = (get-sops-cache-stats)
|
|
let final_stats = (get-final-cache-stats)
|
|
|
|
let summary = [
|
|
{ type: "Nickel Compilation", entries: $nickel_stats.total_entries, size_mb: ($nickel_stats.total_size_mb | math round -p 2) },
|
|
{ type: "SOPS Decryption", entries: $sops_stats.total_entries, size_mb: ($sops_stats.total_size_mb | math round -p 2) },
|
|
{ type: "Final Config", entries: $final_stats.total_entries, size_mb: ($final_stats.total_size_mb | math round -p 2) }
|
|
]
|
|
|
|
match $format {
|
|
"json" => {
|
|
$summary | to json --indent 2 | print
|
|
},
|
|
"yaml" => {
|
|
$summary | to yaml | print
|
|
},
|
|
_ => {
|
|
print "By Type:"
|
|
$summary | table
|
|
}
|
|
}
|
|
}
|
|
|
|
# ============================================================================
|
|
# Helper: Dispatch cache commands
|
|
# ============================================================================
|
|
|
|
# Main cache command dispatcher
|
|
export def main [
|
|
...args: string
|
|
] {
|
|
if ($args | is-empty) {
|
|
cache-status
|
|
return
|
|
}
|
|
|
|
let command = ($args | get 0)
|
|
let rest = (if ($args | length) > 1 { $args | skip 1 } else { [] })
|
|
|
|
match $command {
|
|
"clear" => {
|
|
let cache_type = ($rest | get 0 | default "all")
|
|
cache-clear --type $cache_type
|
|
},
|
|
"list" => {
|
|
cache-list
|
|
},
|
|
"warm" => {
|
|
cache-warm
|
|
},
|
|
"validate" => {
|
|
cache-validate | ignore
|
|
},
|
|
"config" => {
|
|
let subcommand = ($rest | get 0 | default "show")
|
|
match $subcommand {
|
|
"show" => { cache-config-show },
|
|
"get" => {
|
|
let path = ($rest | get 1 | default "")
|
|
if ($path | is-empty) {
|
|
print "Usage: cache config get <setting>"
|
|
} else {
|
|
cache-config-get $path | ignore
|
|
}
|
|
},
|
|
"set" => {
|
|
let path = ($rest | get 1 | default "")
|
|
let value = ($rest | get 2 | default "")
|
|
if ($path | is-empty) or ($value | is-empty) {
|
|
print "Usage: cache config set <setting> <value>"
|
|
} else {
|
|
cache-config-set $path $value
|
|
}
|
|
},
|
|
"reset" => {
|
|
let path = ($rest | get 1 | default "")
|
|
cache-config-reset $path
|
|
},
|
|
"validate" => {
|
|
cache-config-validate | ignore
|
|
},
|
|
_ => {
|
|
print $"Unknown config subcommand: ($subcommand)"
|
|
}
|
|
}
|
|
},
|
|
"status" => {
|
|
cache-status
|
|
},
|
|
"stats" => {
|
|
cache-stats
|
|
},
|
|
"help" => {
|
|
print "Cache Management Commands:
|
|
|
|
cache clear [--type <type>] Clear cache (all, nickel, sops, final)
|
|
cache list List cache entries
|
|
cache warm Pre-populate cache
|
|
cache validate Validate cache integrity
|
|
|
|
cache config show Show configuration
|
|
cache config get <path> Get specific setting
|
|
cache config set <path> <value> Set configuration
|
|
cache config reset [path] Reset to defaults
|
|
cache config validate Validate configuration
|
|
|
|
cache status Show full status (config + stats)
|
|
cache stats Show statistics only
|
|
|
|
cache help Show this help"
|
|
},
|
|
_ => {
|
|
print $"Unknown cache command: ($command)"
|
|
print "Use 'cache help' for available commands"
|
|
}
|
|
}
|
|
}
|