2025-12-11 21:57:05 +00:00
|
|
|
|
# Setup Module - System Setup and Configuration Management
|
|
|
|
|
|
# Orchestrates all setup subcommands with helper functions for configuration management
|
|
|
|
|
|
# Follows Nushell guidelines: explicit types, single purpose, no try-catch
|
|
|
|
|
|
|
|
|
|
|
|
use ../config/accessor.nu *
|
|
|
|
|
|
use ../utils/logging.nu *
|
|
|
|
|
|
|
|
|
|
|
|
# Re-export existing utilities and config helpers
|
|
|
|
|
|
export use utils.nu *
|
|
|
|
|
|
export use config.nu *
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# CONFIGURATION PATH HELPERS
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
# Get OS-appropriate base configuration directory
|
|
|
|
|
|
export def get-config-base-path []: nothing -> string {
|
|
|
|
|
|
match $nu.os-info.name {
|
|
|
|
|
|
"macos" => {
|
|
|
|
|
|
let home = ($env.HOME? | default "~" | path expand)
|
|
|
|
|
|
$"($home)/Library/Application Support/provisioning"
|
|
|
|
|
|
}
|
|
|
|
|
|
"windows" => {
|
|
|
|
|
|
let appdata = ($env.APPDATA? | default "~" | path expand)
|
|
|
|
|
|
$"($appdata)/provisioning"
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
# Default to Linux convention
|
|
|
|
|
|
let home = ($env.HOME? | default "~" | path expand)
|
|
|
|
|
|
$"($home)/.config/provisioning"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get provisioning installation path
|
|
|
|
|
|
export def get-install-path []: nothing -> string {
|
|
|
|
|
|
config-get "setup.install_path" (get-base-path)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get global workspaces directory
|
|
|
|
|
|
export def get-workspaces-dir []: nothing -> string {
|
|
|
|
|
|
let config_base = (get-config-base-path)
|
|
|
|
|
|
$"($config_base)/workspaces"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get cache directory
|
|
|
|
|
|
export def get-cache-dir []: nothing -> string {
|
|
|
|
|
|
let config_base = (get-config-base-path)
|
|
|
|
|
|
$"($config_base)/cache"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# DIRECTORY MANAGEMENT
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
# Ensure configuration directories exist
|
|
|
|
|
|
export def ensure-config-dirs []: nothing -> bool {
|
|
|
|
|
|
let config_base = (get-config-base-path)
|
|
|
|
|
|
let workspaces_dir = (get-workspaces-dir)
|
|
|
|
|
|
let cache_dir = (get-cache-dir)
|
|
|
|
|
|
let platform_dir = $"($config_base)/platform"
|
|
|
|
|
|
let providers_dir = $"($config_base)/providers"
|
|
|
|
|
|
|
|
|
|
|
|
let result_config = (do { mkdir $config_base } | complete)
|
|
|
|
|
|
let result_workspaces = (do { mkdir $workspaces_dir } | complete)
|
|
|
|
|
|
let result_cache = (do { mkdir $cache_dir } | complete)
|
|
|
|
|
|
let result_platform = (do { mkdir $platform_dir } | complete)
|
|
|
|
|
|
let result_providers = (do { mkdir $providers_dir } | complete)
|
|
|
|
|
|
|
|
|
|
|
|
(($result_config.exit_code == 0) and
|
|
|
|
|
|
($result_workspaces.exit_code == 0) and
|
|
|
|
|
|
($result_cache.exit_code == 0) and
|
|
|
|
|
|
($result_platform.exit_code == 0) and
|
|
|
|
|
|
($result_providers.exit_code == 0))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# CONFIGURATION FILE MANAGEMENT
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
# Load TOML configuration file
|
|
|
|
|
|
export def load-config-toml [
|
|
|
|
|
|
file_path: string
|
|
|
|
|
|
]: nothing -> record {
|
|
|
|
|
|
if ($file_path | path exists) {
|
|
|
|
|
|
let file_content = (open $file_path)
|
|
|
|
|
|
match ($file_content | type) {
|
|
|
|
|
|
"record" => $file_content
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
print $"⚠️ Warning: Config file ($file_path) is not a valid TOML record"
|
|
|
|
|
|
{}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
{}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Save TOML configuration file
|
|
|
|
|
|
export def save-config-toml [
|
|
|
|
|
|
file_path: string
|
|
|
|
|
|
config: record
|
|
|
|
|
|
]: nothing -> bool {
|
|
|
|
|
|
let result = (do { $config | to toml | save -f $file_path } | complete)
|
|
|
|
|
|
($result.exit_code == 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Load YAML configuration file
|
|
|
|
|
|
export def load-config-yaml [
|
|
|
|
|
|
file_path: string
|
|
|
|
|
|
]: nothing -> record {
|
|
|
|
|
|
if ($file_path | path exists) {
|
|
|
|
|
|
let file_content = (open $file_path)
|
|
|
|
|
|
match ($file_content | type) {
|
|
|
|
|
|
"record" => $file_content
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
print $"⚠️ Warning: Config file ($file_path) is not a valid YAML record"
|
|
|
|
|
|
{}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
{}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Save YAML configuration file
|
|
|
|
|
|
export def save-config-yaml [
|
|
|
|
|
|
file_path: string
|
|
|
|
|
|
config: record
|
|
|
|
|
|
]: nothing -> bool {
|
|
|
|
|
|
let result = (do { $config | to yaml | save -f $file_path } | complete)
|
|
|
|
|
|
($result.exit_code == 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# SYSTEM INFORMATION DETECTION
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
# Detect operating system
|
|
|
|
|
|
export def detect-os []: nothing -> string {
|
|
|
|
|
|
$nu.os-info.name
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get system architecture
|
|
|
|
|
|
export def detect-architecture []: nothing -> string {
|
|
|
|
|
|
$env.PROCESSOR_ARCHITECTURE? | default $nu.os-info.arch
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get CPU count
|
|
|
|
|
|
export def get-cpu-count []: nothing -> int {
|
|
|
|
|
|
let result = (do {
|
|
|
|
|
|
match (detect-os) {
|
|
|
|
|
|
"macos" => { ^sysctl -n hw.ncpu }
|
|
|
|
|
|
"windows" => {
|
|
|
|
|
|
($env.NUMBER_OF_PROCESSORS? | default "4")
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
^nproc
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} | complete)
|
|
|
|
|
|
|
|
|
|
|
|
if ($result.exit_code == 0) {
|
|
|
|
|
|
($result.stdout | str trim | into int) | default 4
|
|
|
|
|
|
} else {
|
|
|
|
|
|
4
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get system memory in GB
|
|
|
|
|
|
export def get-system-memory-gb []: nothing -> int {
|
|
|
|
|
|
let result = (do {
|
|
|
|
|
|
match (detect-os) {
|
|
|
|
|
|
"macos" => { ^sysctl -n hw.memsize }
|
|
|
|
|
|
"windows" => {
|
|
|
|
|
|
($env.TOTAL_PHYSICAL_MEMORY? | default "8589934592")
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
let mem_kb = (do {
|
|
|
|
|
|
^grep -i memtotal /proc/meminfo | awk '{print $2}'
|
|
|
|
|
|
} | complete)
|
|
|
|
|
|
if ($mem_kb.exit_code == 0) {
|
|
|
|
|
|
($mem_kb.stdout | str trim)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
"8388608"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} | complete)
|
|
|
|
|
|
|
|
|
|
|
|
if ($result.exit_code == 0) {
|
|
|
|
|
|
let bytes = ($result.stdout | str trim | into int) | default 8589934592
|
|
|
|
|
|
($bytes / 1_000_000_000 | math floor) | default 8
|
|
|
|
|
|
} else {
|
|
|
|
|
|
8
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get system disk space in GB
|
|
|
|
|
|
export def get-system-disk-gb []: nothing -> int {
|
|
|
|
|
|
let home_dir = ($env.HOME? | default "~" | path expand)
|
|
|
|
|
|
let result = (do {
|
|
|
|
|
|
^df -H $home_dir | tail -n 1 | awk '{print $2}'
|
|
|
|
|
|
} | complete)
|
|
|
|
|
|
|
|
|
|
|
|
if ($result.exit_code == 0) {
|
|
|
|
|
|
let size_str = ($result.stdout | str trim)
|
|
|
|
|
|
($size_str | str replace -a 'G' '' | str replace -a 'T' '000' | str trim | into int) | default 100
|
|
|
|
|
|
} else {
|
|
|
|
|
|
100
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get current timestamp in ISO 8601 format
|
|
|
|
|
|
export def get-timestamp-iso8601 []: nothing -> string {
|
|
|
|
|
|
(date now | format date "%Y-%m-%dT%H:%M:%SZ")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get current user
|
|
|
|
|
|
export def get-current-user []: nothing -> string {
|
|
|
|
|
|
$env.USER? | default $env.USERNAME? | default "unknown"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get system hostname
|
|
|
|
|
|
export def get-system-hostname []: nothing -> string {
|
|
|
|
|
|
let result = (do { ^hostname } | complete)
|
|
|
|
|
|
|
|
|
|
|
|
if ($result.exit_code == 0) {
|
|
|
|
|
|
$result.stdout | str trim
|
|
|
|
|
|
} else {
|
|
|
|
|
|
"unknown"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# SETUP MESSAGE HELPERS
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
# Print setup section header
|
|
|
|
|
|
export def print-setup-header [
|
|
|
|
|
|
title: string
|
|
|
|
|
|
]: nothing -> nothing {
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print $"🔧 ($title)"
|
|
|
|
|
|
print "════════════════════════════════════════════════════════════════"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Print setup success message
|
|
|
|
|
|
export def print-setup-success [
|
|
|
|
|
|
message: string
|
|
|
|
|
|
]: nothing -> nothing {
|
|
|
|
|
|
print $"✅ ($message)"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Print setup warning message
|
|
|
|
|
|
export def print-setup-warning [
|
|
|
|
|
|
message: string
|
|
|
|
|
|
]: nothing -> nothing {
|
|
|
|
|
|
print $"⚠️ ($message)"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Print setup error message
|
|
|
|
|
|
export def print-setup-error [
|
|
|
|
|
|
message: string
|
|
|
|
|
|
]: nothing -> nothing {
|
|
|
|
|
|
print $"❌ ($message)"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Print setup info message
|
|
|
|
|
|
export def print-setup-info [
|
|
|
|
|
|
message: string
|
|
|
|
|
|
]: nothing -> nothing {
|
|
|
|
|
|
print $"ℹ️ ($message)"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# SETUP COMMAND DISPATCHER
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
# Main setup dispatcher - routes to appropriate subcommand
|
|
|
|
|
|
export def setup-dispatch [
|
|
|
|
|
|
command: string
|
|
|
|
|
|
args: list<string>
|
|
|
|
|
|
--verbose = false
|
|
|
|
|
|
]: nothing -> nothing {
|
|
|
|
|
|
|
|
|
|
|
|
# Ensure config directories exist before any setup operation
|
|
|
|
|
|
if not (ensure-config-dirs) {
|
|
|
|
|
|
print-setup-error "Failed to create configuration directories"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
match $command {
|
|
|
|
|
|
"system" => {
|
|
|
|
|
|
print-setup-info "System setup not yet implemented"
|
|
|
|
|
|
}
|
|
|
|
|
|
"workspace" => {
|
|
|
|
|
|
print-setup-info "Workspace setup not yet implemented"
|
|
|
|
|
|
}
|
|
|
|
|
|
"provider" => {
|
|
|
|
|
|
print-setup-info "Provider setup not yet implemented"
|
|
|
|
|
|
}
|
|
|
|
|
|
"platform" => {
|
|
|
|
|
|
print-setup-info "Platform setup not yet implemented"
|
|
|
|
|
|
}
|
|
|
|
|
|
"update" => {
|
|
|
|
|
|
print-setup-info "Setup update not yet implemented"
|
|
|
|
|
|
}
|
|
|
|
|
|
"wizard" => {
|
|
|
|
|
|
print-setup-info "Interactive wizard not yet implemented"
|
|
|
|
|
|
}
|
|
|
|
|
|
"validate" => {
|
|
|
|
|
|
print-setup-info "Setup validation not yet implemented"
|
|
|
|
|
|
}
|
|
|
|
|
|
"migrate" => {
|
|
|
|
|
|
print-setup-info "Setup migration not yet implemented"
|
|
|
|
|
|
}
|
|
|
|
|
|
"detect" => {
|
|
|
|
|
|
print-setup-header "System Detection Results"
|
|
|
|
|
|
print $"Operating System: (detect-os)"
|
|
|
|
|
|
print $"Architecture: (detect-architecture)"
|
|
|
|
|
|
print $"CPU Count: (get-cpu-count)"
|
|
|
|
|
|
print $"Memory (GB): (get-system-memory-gb)"
|
|
|
|
|
|
print $"Disk (GB): (get-system-disk-gb)"
|
|
|
|
|
|
print $"Hostname: (get-system-hostname)"
|
|
|
|
|
|
print $"Current User: (get-current-user)"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
print-setup-error $"Unknown setup command: ($command)"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "Available setup commands:"
|
|
|
|
|
|
print " system - Complete system setup"
|
|
|
|
|
|
print " workspace - Create new workspace"
|
|
|
|
|
|
print " provider - Configure provider"
|
|
|
|
|
|
print " platform - Setup platform services"
|
|
|
|
|
|
print " update - Update existing configuration"
|
|
|
|
|
|
print " wizard - Interactive setup wizard"
|
|
|
|
|
|
print " validate - Validate configuration"
|
|
|
|
|
|
print " migrate - Migrate existing configuration"
|
|
|
|
|
|
print " detect - Show detected system information"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# MODULE INITIALIZATION
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
# Initialize setup module
|
|
|
|
|
|
export def setup-init []: nothing -> bool {
|
|
|
|
|
|
ensure-config-dirs
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get setup module version
|
|
|
|
|
|
export def get-setup-version []: nothing -> string {
|
|
|
|
|
|
"1.0.0"
|
|
|
|
|
|
}
|