syntaxis/scripts/provisioning/install-with-presets.nu
Jesús Pérez 9cef9b8d57 refactor: consolidate configuration directories
Merge _configs/ into config/ for single configuration directory.
Update all path references.

Changes:
- Move _configs/* to config/
- Update .gitignore for new patterns
- No code references to _configs/ found

Impact: -1 root directory (layout_conventions.md compliance)
2025-12-26 18:36:23 +00:00

531 lines
16 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env nu
# install-with-presets.nu - Local syntaxis installer with preset reference
#
# This script handles LOCAL installation and setup only.
# For remote/distributed deployments, use project-provisioning:
# https://github.com/Akasha/project-provisioning
#
# This script:
# - Installs syntaxis binaries locally
# - Configures local services (optional)
# - Shows preset templates (reference only)
#
# Architecture:
# syntaxis: Binary distribution + LOCAL installation
# project-provisioning: Remote infrastructure + multi-host orchestration
#
# USAGE:
# nu scripts/provisioning/install-with-presets.nu --preset local
# nu scripts/provisioning/install-with-presets.nu --list-presets
# nu scripts/provisioning/install-with-presets.nu help
def main [
--preset: string = "local"
--verbose: bool = false
--list-presets: bool = false
...args
] {
# Handle help and list commands
let first_arg = ($args | first)
if ($first_arg == "help") or ($first_arg == "--help") or ($first_arg == "-h") {
print_help
return
}
if $list_presets or ($first_arg == "list-presets") {
list_available_presets
return
}
print_header
# Only allow LOCAL presets that make sense for this machine
let allowed_local_presets = ["minimal", "local", "dev"]
if not ($preset in $allowed_local_presets) {
print "❌ Error: preset '$preset' is not supported for local installation"
print ""
print "For remote deployments (staging, production, kubernetes),"
print "use project-provisioning:"
print " https://github.com/Akasha/project-provisioning"
print ""
print "Allowed LOCAL presets:"
$allowed_local_presets | each { |p| print $" • ($p)" }
return
}
print_divider
print $"Selected preset: (ansi cyan)($preset)(ansi reset)"
# Load preset configuration (for reference)
let install_config = load_preset_reference $preset
if ($install_config == null) {
print $"❌ Unknown preset: ($preset)"
return
}
# Show preset information
print_preset_info $preset $install_config
# Pre-flight checks (minimal)
print_divider
print "✓ Running pre-flight checks..."
let checks_passed = (run_preflight_checks_local $preset)
if not $checks_passed {
print "⚠️ Some checks failed - proceed anyway? (y/n)"
# For automation, continue anyway
}
# Check provctl availability
print_divider
print "🔍 Checking environment..."
let provctl_info = (detect_provctl_availability)
let provctl_available = ($provctl_info.available)
if $verbose {
print $" provctl available: ($provctl_available)"
if $provctl_available {
print $" provctl path: ($provctl_info.path)"
print $" provctl version: ($provctl_info.version)"
}
}
# Determine provctl usage
let use_provctl = match $provctl {
"required" => {
if not $provctl_available {
print "❌ provctl is required but not available"
print "Install from: https://github.com/Akasha/provctl"
return
}
true
}
"disabled" => false
"auto" => {
if $provctl_available and ($preset_config.provctl_recommended? ?? false) {
true
} else {
false
}
}
_ => false
}
if $use_provctl {
print "✓ provctl will be used for service management"
} else {
print " Service management: manual setup (generate scripts)"
}
# Installation phase
print_divider
print "📦 Installing syntaxis binaries..."
# Determine which binaries to install based on preset
let binaries_to_install = (get_binaries_for_preset $effective_preset $preset_config)
if ($binaries_to_install | length) == 0 {
print " No binaries to install for this preset"
} else {
# Call the original installer
print $"Installing ($binaries_to_install | length) binary(ies)..."
try {
# Run original installer for binaries
nu scripts/install-syntaxis.nu all 2>/dev/null
print "✓ Binaries installed"
} catch { |err|
print $"⚠️ Binary installation had issues: ($err)"
}
}
# Service setup phase
let services_config = ($preset_config.services?)
if ($services_config != null) {
print_divider
print "🚀 Setting up services..."
setup_services $effective_preset $services_config $use_provctl $provctl_info
}
# Database configuration
print_divider
print "🗄️ Configuring database..."
let db_backend = ($preset_config.database_backend? ?? "sqlite")
setup_database $db_backend $effective_preset
# Create manifest
print_divider
print "📋 Creating installation manifest..."
create_installation_manifest $effective_preset $preset_config $use_provctl
# Summary and next steps
print_divider
print_installation_summary $effective_preset $preset_config
}
# Load configuration from file
def load_config_from_file [config_path: string] {
if not ($config_path | path exists) {
print $"⚠️ Configuration not found: ($config_path)"
return null
}
try {
open $config_path
} catch { |err|
print $"❌ Failed to load configuration: ($err)"
return null
}
}
# Generate installation config output
def generate_installation_config [preset: string, config: record]: nothing -> string {
let output = $"# Generated installation configuration for preset: ($preset)
[installation]
preset = \"($preset)\"
interactive = false
[database]
backend = \"($config.database_backend?)\"
[services]
"
# Add services
let services_str = (
if ($config.services? != null) {
($config.services | to toml)
} else {
""
}
)
$output + $services_str
}
# Detect provctl availability
def detect_provctl_availability []: nothing -> record {
try {
nu scripts/provisioning/detect-provctl.nu
} catch {
{
available: false,
path: null,
version: null,
commands: [],
backends: []
}
}
}
# Select preset interactively
def select_preset_interactive [config: record]: nothing -> string {
let available_presets = ($config | get preset | keys)
if ($available_presets | length) == 0 {
return "local"
}
print ""
print "Available installation presets:"
print ""
for (idx, preset) in ($available_presets | enumerate) {
let preset_info = ($config.preset | get $preset)
let name = ($preset_info.name? ?? $preset)
let desc = ($preset_info.description? ?? "")
print $" ($idx + 1)) ($name)"
if ($desc != "") {
print $" ($desc)"
}
print ""
}
# Get user input
let choice = (input "Select preset (1-$(($available_presets | length)): ")
let choice_num = (try { $choice | into int } catch { 1 })
if ($choice_num > 0) and ($choice_num <= ($available_presets | length)) {
$available_presets | get ($choice_num - 1)
} else {
"local"
}
}
# Get binaries for preset
def get_binaries_for_preset [preset: string, config: record]: nothing -> list {
["syntaxis-cli", "syntaxis-tui"] # Core binaries always installed
# API and others conditional on preset
}
# Setup database
def setup_database [backend: string, preset: string] {
print $"Database backend: (ansi cyan)($backend)(ansi reset)"
match $backend {
"sqlite" => {
let db_path = "~/.local/share/core/workspace.db"
print $" Location: ($db_path)"
print $" Status: File-based (automatic)"
}
"surrealdb" => {
print $" Mode: Check configs/database-surrealdb.toml"
print $" Status: Requires configuration"
}
_ => {
print $" Unknown backend: ($backend)"
}
}
}
# Setup services
def setup_services [preset: string, services: record, use_provctl: bool, provctl_info: record] {
print $"Services for preset: (ansi cyan)($preset)(ansi reset)"
let service_list = []
# Iterate through services
try {
$services | transpose | each { |item|
let service_name = $item.key
let service_config = $item.value
if ($service_config.enabled? ?? false) {
print $" ✓ ($service_name)"
if ($service_config.auto_start? ?? false) {
print $" └─ auto-start: enabled"
}
}
}
} catch {
print " (no services configured)"
}
if $use_provctl {
print ""
print "📌 Service deployment with provctl:"
print " Run: nu scripts/provisioning/provctl-services.nu deploy $preset"
}
}
# Create installation manifest
def create_installation_manifest [preset: string, config: record, used_provctl: bool] {
let manifest_path = ".syntaxis/manifest-installation.toml"
let timestamp = (date now | format date "%Y-%m-%d %H:%M:%S")
let manifest = $"# Installation Manifest
[installation]
preset = \"($preset)\"
timestamp = \"($timestamp)\"
provctl_used = ($used_provctl)
config_location = \"configs/installation.toml\"
[preset_info]
name = \"($config.name?)\"
description = \"($config.description?)\"
[database]
backend = \"($config.database_backend?)\"
[notes]
# To view services: nu scripts/provisioning/provctl-services.nu list $preset
# To manage services: nu scripts/provisioning/provctl-services.nu deploy $preset
"
try {
^mkdir -p .syntaxis
echo $manifest | save $manifest_path
print $"✓ Manifest saved: ($manifest_path)"
} catch { |err|
print $"⚠️ Failed to create manifest: ($err)"
}
}
# Print header
def print_header [] {
print ""
print "┌────────────────────────────────────────────────┐"
print "│ syntaxis Enhanced Installer with provctl │"
print "│ Smart presets + Service Management │"
print "└────────────────────────────────────────────────┘"
print ""
}
# Print divider
def print_divider [] {
print "─────────────────────────────────────────────────"
}
# Print preset info
def print_preset_info [name: string, config: record] {
print $"Preset: (ansi cyan)($name)(ansi reset)"
print $" Name: ($config.name?)"
print $" Description: ($config.description?)"
print $" Database: ($config.database_backend?)"
}
# Print installation summary
def print_installation_summary [preset: string, config: record] {
print "Installation complete!"
print ""
print "Next steps:"
match $preset {
"local" => {
print " 1. Try the CLI: syntaxis-cli init my-project"
print " 2. Use TUI: syntaxis-tui"
print ""
print "To upgrade later: nu scripts/provisioning/install-with-presets.nu --preset dev"
}
"dev" => {
print " 1. Start services: provctl start surrealdb && provctl start nats"
print " 2. Or use: docker-compose up"
print " 3. Open dashboard: http://localhost:3000"
print " 4. Use API: curl http://localhost:3000/health"
}
"staging" => {
print " 1. Start Docker services: docker-compose -f docker/docker-compose.yml up"
print " 2. Verify health: curl http://localhost:3000/health"
print " 3. Open dashboard: http://localhost:3000"
print " 4. Monitor: http://localhost:9090"
}
"production" => {
print " 1. Review Kubernetes manifests: ls kubernetes/"
print " 2. Create namespace: kubectl create namespace syntaxis"
print " 3. Deploy: kubectl apply -f kubernetes/"
print " 4. Monitor: kubectl logs -n syntaxis deployment/syntaxis-api"
}
_ => {
print " Installation complete. Run 'syntaxis-cli --help' for usage."
}
}
print ""
print "Documentation: docs/INSTALLATION_CONTEXTS.md"
print ""
}
# Print help message
def print_help [] {
print ""
print "syntaxis Enhanced Installer with Presets and provctl Integration"
print ""
print "USAGE:"
print " nu scripts/provisioning/install-with-presets.nu [OPTIONS]"
print ""
print "OPTIONS:"
print " --preset <PRESET> Installation preset (local, minimal, dev, staging, production, custom)"
print " --interactive Interactive mode - ask questions"
print " --config <FILE> Load configuration from file"
print " --generate-config Generate config file and exit"
print " --provctl <MODE> provctl mode: auto (default), required, disabled"
print " --verbose Verbose output"
print " --list-presets List all available presets"
print " -h, --help Show this help message"
print ""
print "EXAMPLES:"
print " # Simple local installation"
print " nu scripts/provisioning/install-with-presets.nu"
print ""
print " # Development with services"
print " nu scripts/provisioning/install-with-presets.nu --preset dev"
print ""
print " # Interactive setup"
print " nu scripts/provisioning/install-with-presets.nu --interactive"
print ""
print " # Generate configuration"
print " nu scripts/provisioning/install-with-presets.nu --preset staging --generate-config"
print ""
print " # Install from configuration file"
print " nu scripts/provisioning/install-with-presets.nu --config my-install.toml"
print ""
print "DOCUMENTATION:"
print " docs/INSTALLATION_CONTEXTS.md - Detailed guide for each preset"
print " CLAUDE.md - Installation commands reference"
print ""
}
# List all available presets
def list_available_presets [] {
let config = (
try {
open "configs/installation.toml"
} catch {
return
}
)
let presets = ($config | get preset | keys | sort)
print ""
print "Available Installation Presets:"
print ""
for preset in $presets {
let preset_config = ($config.preset | get $preset)
let name = ($preset_config.name? ?? $preset)
let desc = ($preset_config.description? ?? "No description")
let db = ($preset_config.database_backend? ?? "unknown")
print $" (ansi cyan)→(ansi reset) ($preset)"
print $" Name: ($name)"
print $" Description: ($desc)"
print $" Database: ($db)"
print ""
}
}
# Run pre-flight checks
def run_preflight_checks [preset: string]: nothing -> bool {
mut all_passed = true
# Check if Rust is installed
if (try { which cargo } catch { null }) == null {
print " ⚠️ Rust/Cargo not found (required for building)"
$all_passed = false
} else {
print " ✓ Rust/Cargo detected"
}
# Check if NuShell is available
if (try { which nu } catch { null }) == null {
print " ❌ NuShell required but not found"
return false
} else {
print " ✓ NuShell detected"
}
# Check if configs exist
if not ("configs/installation.toml" | path exists) {
print " ❌ configs/installation.toml not found"
return false
} else {
print " ✓ Installation config found"
}
# Preset-specific checks
match $preset {
"dev" | "staging" => {
if (try { which surreal } catch { null }) == null {
print " ⚠️ SurrealDB CLI not found (can install with: cargo install surrealdb-cli)"
# Not fatal, warn but continue
} else {
print " ✓ SurrealDB detected"
}
}
"staging" | "production" => {
if (try { which docker } catch { null }) == null {
print " ⚠️ Docker not found (required for this preset)"
$all_passed = false
} else {
print " ✓ Docker detected"
}
}
_ => {}
}
$all_passed
}