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

416 lines
12 KiB
Plaintext

#!/usr/bin/env nu
# provctl - Provisioning orchestrator
#
# Coordinates pack, unpack, install, and deploy operations
#
# Usage:
# nu scripts/provisioning/provctl.nu build-bundle --target x86_64-linux
# nu scripts/provisioning/provctl.nu install-bundle bundle.tar.gz
# nu scripts/provisioning/provctl.nu status
#
def show-help [] {
print "
provctl - syntaxis Provisioning Orchestrator
USAGE:
nu scripts/provisioning/provctl.nu <ACTION> [OPTIONS]
ACTIONS:
build-bundle Create a distribution bundle
install-bundle Extract and install a bundle
deploy-bundle Deploy configs from extracted bundle
full-install Extract, install, and deploy (complete setup)
status Show installation status
list-targets List available build targets
verify-bundle Verify bundle integrity
clean Clean staging directories
help Show this help message
OPTIONS (build-bundle):
--target <TARGET> Target triple (e.g., x86_64-unknown-linux-gnu)
--format <FORMAT> Package format (tar.gz, zip, deb, rpm)
--output <DIR> Output directory
--verify Verify bundle after creation
OPTIONS (install-bundle):
--bundle <FILE> Bundle file path
--dest <DIR> Extraction destination
--prefix <PATH> Installation prefix
--force Force overwrite
OPTIONS (deploy-bundle):
--source <DIR> Source bundle directory
--config-dir <PATH> Target config directory
--backup Backup existing configs
OPTIONS (full-install):
--bundle <FILE> Bundle file
--prefix <PATH> Installation prefix
--config-dir <PATH> Config directory
--verify Verify throughout
EXAMPLES:
# Build bundle for current platform
provctl build-bundle
# Build bundle for Linux
provctl build-bundle --target x86_64-unknown-linux-gnu --output dist/
# Show available targets
provctl list-targets
# Extract bundle
provctl install-bundle --bundle ./bundle.tar.gz --prefix ~/.local
# Complete installation from bundle
provctl full-install --bundle ./bundle.tar.gz --verify
# Check installation status
provctl status
"
}
def action-build-bundle [--target: string = "", --format: string = "tar.gz", --output: path = "dist/", --verify = false] {
print "🔨 Building distribution bundle..."
print ""
let args = [
"scripts/provisioning/pack.nu"
(if ($target != "") { ["--target", $target] } else { [] })
(if ($format != "tar.gz") { ["--format", $format] } else { [] })
(if ($output != "dist/") { ["--output", ($output | into string)] } else { [] })
(if $verify { ["--verify"] } else { [] })
] | flatten
try {
nu ...$args
} catch {
error make {msg: "Failed to build bundle"}
}
}
def action-install-bundle [--bundle: path = "", --dest: path = ".", --prefix: path = "", --force = false] {
if ($bundle == "") {
error make {msg: "Bundle file must be specified with --bundle"}
}
if (not (($bundle | path exists))) {
let msg = "Bundle file not found: " + ($bundle | into string)
error make {msg: $msg}
}
print "📦 Installing bundle..."
print ""
let args = [
"scripts/provisioning/unpack.nu"
($bundle | into string)
"--dest"
($dest | into string)
] | flatten
try {
nu ...$args
} catch {
error make {msg: "Failed to extract bundle"}
}
# Find extracted bundle and install
print ""
print "📂 Installing binaries..."
let bundle_dirs = (
glob ($dest | path join "*")
| where {|d| (($d | path type) == "dir")}
)
if ($bundle_dirs | is-empty) {
error make {msg: "No bundle directory found after extraction"}
}
let bundle_root = $bundle_dirs.0
let prefix_arg = if ($prefix == "") { [] } else { ["--prefix", ($prefix | into string)] }
let install_args = [
"scripts/provisioning/install.nu"
"--source"
($bundle_root | path join "bin" | into string)
...$prefix_arg
(if $force { ["--force"] } else { [] })
] | flatten
try {
nu ...$install_args
} catch {
error make {msg: "Failed to install binaries"}
}
}
def action-deploy-bundle [--source: path = "", --config-dir: path = "", --backup = false] {
if ($source == "") {
error make {msg: "Source directory must be specified with --source"}
}
if (not (($source | path exists))) {
let msg = "Source directory not found: " + ($source | into string)
error make {msg: $msg}
}
print "⚙️ Deploying configuration files..."
print ""
let config_arg = if ($config_dir == "") { [] } else { ["--config-dir", ($config_dir | into string)] }
let args = [
"scripts/provisioning/deploy.nu"
"--source"
($source | into string)
...$config_arg
(if $backup { ["--backup"] } else { [] })
] | flatten
try {
nu ...$args
} catch {
error make {msg: "Failed to deploy configs"}
}
}
def action-full-install [--bundle: path = "", --prefix: path = "", --config-dir: path = "", --verify = false] {
if ($bundle == "") {
error make {msg: "Bundle file must be specified with --bundle"}
}
if (not (($bundle | path exists))) {
let msg = "Bundle file not found: " + ($bundle | into string)
error make {msg: $msg}
}
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print "🚀 syntaxis Full Installation"
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print ""
# Step 1: Extract
print "📦 Step 1: Extracting bundle..."
let temp_dir = (
"/tmp" | path join "syntaxis-install" (date now | format date "%s")
)
^mkdir -p $temp_dir
try {
action-install-bundle --bundle $bundle --dest $temp_dir --prefix $prefix --force true
} catch {
^rm -rf $temp_dir
error make {msg: "Installation failed during extraction"}
}
# Find extracted bundle
let bundle_dirs = (
glob ($temp_dir | path join "*")
| where {|d| (($d | path type) == "dir")}
)
if ($bundle_dirs | is-empty) {
^rm -rf $temp_dir
error make {msg: "No bundle directory found"}
}
let bundle_root = $bundle_dirs.0
# Step 2: Deploy configs
print ""
print "⚙️ Step 2: Deploying configuration files..."
try {
action-deploy-bundle --source $bundle_root --config-dir $config_dir --backup true
} catch {
^rm -rf $temp_dir
error make {msg: "Installation failed during config deployment"}
}
# Cleanup
^rm -rf $temp_dir
print ""
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print "✅ Installation complete!"
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
}
def action-status [] {
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print "📊 Installation Status"
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print ""
# Check manifest
let manifest_dir = ($env.HOME | path join ".syntaxis")
let manifest_file = ($manifest_dir | path join "manifest.toml")
if (not (($manifest_file | path exists))) {
print "⚠️ No installation manifest found"
print " Run: provctl full-install --bundle <file>"
return
}
try {
let manifest = (open --raw $manifest_file | from toml)
print "Installation Details:"
print (" Timestamp: " + ($manifest.installation.installed_at | into string))
print (" Prefix: " + ($manifest.installation.prefix | into string))
print ""
print ("Installed Binaries: " + (($manifest.installation.binaries | length) | into string))
$manifest.installation.binaries | each {|binary_name|
print (" ✓ " + ($binary_name | into string))
}
} catch {
print "⚠️ Could not read installation manifest"
}
# Check deployment manifest
let deploy_manifest = ($manifest_dir | path join "deployment.toml")
if (($deploy_manifest | path exists)) {
try {
let manifest = (open --raw $deploy_manifest | from toml)
print ""
print ("Deployed Configs: " + (($manifest.deployment.configs | length) | into string))
$manifest.deployment.configs | each {|config|
print (" ✓ " + ($config | into string))
}
} catch { }
}
print ""
}
def action-list-targets [] {
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print "🎯 Available Build Targets"
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print ""
try {
nu scripts/provisioning/pack.nu --list-targets
} catch {
error make {msg: "Failed to list targets"}
}
}
def action-verify-bundle [--bundle: path = ""] {
if ($bundle == "") {
let msg = "Bundle file must be specified with --bundle"
error make {msg: $msg}
}
if (not (($bundle | path exists))) {
let msg = "Bundle not found: " + ($bundle | into string)
error make {msg: $msg}
}
print "🔍 Verifying bundle..."
print ""
# Validate structure
let ext = ($bundle | path parse | get extension)
let valid_format = (($ext == "gz") or ($ext == "zip"))
if $valid_format {
print ("✅ Bundle format valid: " + ($ext | into string))
} else {
error make {msg: "Invalid bundle format (expected .tar.gz or .zip)"}
}
# Check size
let size_mb = (((ls $bundle | get size.0) | into int) / (1024 * 1024) | math round --precision 2)
print ("✅ Bundle size: " + ($size_mb | into string) + " MB")
# Check checksums file
let bundle_name = ($bundle | path parse | get stem)
let checksums_file = (
($bundle | path dirname)
| path join ($bundle_name + ".checksums.toml")
)
if (($checksums_file | path exists)) {
print "✅ Checksums file found"
} else {
print "⚠️ Checksums file not found"
}
print ""
print "✅ Bundle verification complete"
}
def action-clean [] {
print "🧹 Cleaning staging directories..."
let staging_dirs = [
".provisioning-staging"
"/tmp/syntaxis-install"
]
$staging_dirs | each {|dir|
if (($dir | path exists)) {
^rm -rf $dir
print (" ✓ Removed: " + ($dir | into string))
}
}
print "✅ Cleanup complete"
}
def main [action: string = "", ...args: string] {
match $action {
"build-bundle" => {
action-build-bundle
}
"install-bundle" => {
action-install-bundle
}
"deploy-bundle" => {
action-deploy-bundle --source "."
}
"full-install" => {
action-full-install
}
"status" => {
action-status
}
"list-targets" => {
action-list-targets
}
"verify-bundle" => {
action-verify-bundle
}
"clean" => {
action-clean
}
"help" | "--help" | "-h" => {
show-help
}
"" => {
show-help
}
_ => {
print ("Unknown action: " + ($action | into string))
print ""
show-help
}
}
}
# Parse args and execute
let action = if (($in | length) > 0) { $in.0 } else { "" }