syntaxis/scripts/install-syntaxis.nu

889 lines
32 KiB
Plaintext
Raw Normal View History

#!/usr/bin/env nu
# syntaxis Installer (Dynamic Binary Discovery)
#
# Dynamically discovers binary crates from workspace Cargo.toml
# and installs them with wrappers, configs, and Leptos deployment
#
# USAGE:
# install-syntaxis.nu # Show help
# install-syntaxis.nu help # Show help
# install-syntaxis.nu all # Install all binaries (keeps target/)
# install-syntaxis.nu all --rm-target # Install all (remove target/)
# install-syntaxis.nu status # Show installation status
# install-syntaxis.nu list # List available binaries
# Source shared libraries
source syntaxis-lib.nu
def print_help [] {
print ""
print "🛠️ syntaxis Binary Installer"
print ""
print "Dynamically installs binaries from workspace with configs and Leptos dashboard"
print ""
print "USAGE:"
print " install-syntaxis.nu # Show this help message"
print " install-syntaxis.nu help # Show this help message"
print " install-syntaxis.nu all # Install all binaries (keeps target/)"
print " install-syntaxis.nu all --rm-target # Install all and remove target/"
print " install-syntaxis.nu status # Show installation status"
print " install-syntaxis.nu list # List available binaries"
print ""
print "INSTALL SPECIFIC BINARIES:"
print " install-syntaxis.nu cli # Install syntaxis-cli"
print " install-syntaxis.nu tui # Install syntaxis-tui"
print " install-syntaxis.nu api # Install syntaxis-api"
print " install-syntaxis.nu client # Install dashboard-client"
print ""
print " # Or use full binary/crate names:"
print " install-syntaxis.nu syntaxis-cli # Install syntaxis-cli"
print " install-syntaxis.nu syntaxis-tui # Install syntaxis-tui"
print " install-syntaxis.nu syntaxis-api # Install syntaxis-api"
print ""
print "OPTIONS:"
print " --rm-target # Remove target/ directories after build"
print " # (default: false, keep target/)"
print ""
print "WHAT GETS INSTALLED (PER BINARY):"
print " 1. Binary crate (auto-discovered from Cargo.toml [[bin]] sections)"
print " 2. Wrapper script (for binaries that need configuration)"
print " • Injects environment variables for auto-discovery binaries"
print " • Injects default --config path"
print " 3. Target-specific config file"
print ""
print "GLOBAL RESOURCES:"
print " • Installation manifest in .syntaxis/manifest.toml"
print " • Configuration directories at ~/.config/syntaxis/"
print ""
}
def discover_binary_crates [] {
# Load workspace members from root Cargo.toml and find binaries in core/crates/*
let workspace_toml = "Cargo.toml"
if not ($workspace_toml | path exists) {
print "❌ Cargo.toml not found"
return []
}
try {
# Read root Cargo.toml to get workspace members
let workspace_content = (open $workspace_toml)
# Extract all lines with members entries
let members = (
($workspace_content | get -o workspace | get -o members)
| each { |line|
# let trimmed = ($line | str trim)
# Match entries like "core/crates/syntaxis-api",
if ($line | str starts-with 'core/crates/') {
# Extract the path: "core/crates/syntaxis-api", → core/crates/syntaxis-api
# Split by quotes and get the middle part
($line | str trim)
#let parts = ($line | split row '"')
#if ($parts | length) >= 2 {
# $parts | get 1
#}
}
}
| compact
)
# For each member in core/crates/*, extract metadata
let binaries = (
$members
| each { |member_path|
let member_toml = $"($member_path)/Cargo.toml"
if ($member_toml | path exists) {
let member_content = (open $member_toml)
# Extract package name
let package_name = ($member_content | get -o package | get -o name)
if ($package_name | is-not-empty) {
# Extract metadata from [package.metadata.syntaxis]
let metadata = ($member_content | get -o package.metadata | get -o syntaxis)
if ($metadata | is-not-empty) {
# Extract use_wrapper
let use_wrapper = ($metadata | get -o use_wrapper)
# Extract install_mode
let install_mode = ($metadata | get -o install_mode)
# Extract config_src
let config_src = ($metadata | get -o config_src)
# Extract binary name from [[bin]] section
let parts_bin = ($member_content | get -o bin)
let bin_name = if ($parts_bin | length) > 0 {
$parts_bin | first | get -o name
} else {
""
}
let binary_name = if ($bin_name | is-not-empty) {
$bin_name
} else {
$package_name
}
# Return record directly
{
crate_name: $package_name,
binary_name: $binary_name,
crate_path: $member_path,
use_wrapper: $use_wrapper,
install_mode: $install_mode,
config_src: $config_src
}
}
}
}
}
| compact
)
return $binaries
} catch { |err|
print $"❌ Failed to discover binaries: ($err)"
return []
}
}
def deploy_libs [binaries: list] {
# Copy syntaxis-lib.nu and target-specific scripts/libs to ~/.config/syntaxis/scripts/
# so wrappers can import them via NU_LIB_DIRS
# Only archives/backs up scripts for the specific binaries being installed (NOT the shared lib)
let config_scripts_dir = ($env.HOME + "/.config/syntaxis/scripts")
let config_dir = ($env.HOME + "/.config/syntaxis")
let scripts_dir = ($env.PWD + "/scripts")
try {
# Create config scripts directory
^mkdir -p $config_scripts_dir
# Copy common library WITHOUT backup (shared across all binaries)
let lib_path = ($scripts_dir + "/syntaxis-lib.nu")
if ($lib_path | path exists) {
let lib_dest = ($config_scripts_dir + "/syntaxis-lib.nu")
# Deploy without backup - syntaxis-lib.nu is shared and shouldn't be archived on every install
^cp $lib_path $lib_dest
print " ✅ Deployed syntaxis-lib.nu to config (no backup)"
} else {
print $" ⚠️ syntaxis-lib.nu not found at ($lib_path)"
}
# Extract binary names from the binaries list to determine which scripts to deploy
let binary_names = ($binaries | each { |b| $b.binary_name })
# Copy target-specific libraries and scripts only for binaries being installed
# For each binary with binary_name "syntaxis-tui", deploy: syntaxis-tui.nu and syntaxis-tui-lib.nu
# These ARE backed up to archives before overwriting
let target_files = (glob ($scripts_dir + "/syntaxis-*.nu") | compact)
if ($target_files | length) > 0 {
for file_path in $target_files {
let file_name = ($file_path | path basename)
# Skip the shared library (already handled above without backup)
if ($file_name == "syntaxis-lib.nu") {
continue
}
# Check if this script belongs to any of the binaries being installed
# binary_name already includes "syntaxis-" prefix (e.g., "syntaxis-tui")
# so we check for exact filename matches like "syntaxis-tui.nu" and "syntaxis-tui-lib.nu"
let should_deploy = ($binary_names | any { |bn|
($file_name == $"($bn).nu") or ($file_name == $"($bn)-lib.nu")
})
if $should_deploy {
let script_dest = ($config_scripts_dir + "/" + $file_name)
# Backup existing script if it exists (to parent config_dir archives)
backup_if_exists $script_dest $config_dir
^cp $file_path $script_dest
print $" ✅ Deployed ($file_name)"
}
}
} else {
print " No target-specific scripts found"
}
} catch { |err|
print $" ⚠️ Failed to deploy libs: ($err)"
}
}
def install_binary [item: record , rm_target: bool] {
let display_name = $"(ansi blue)($item.crate_name)(ansi reset)"
print $"📦 Building ($display_name) [from: ($item.crate_path) wrapper: ($item.use_wrapper) mode: ($item.install_mode)] config: ($item.config_src)] ..."
try {
if ($item.install_mode == "cargo") or ($item.install_mode | str starts-with "cargo") {
# Standard cargo install
cargo install --path $item.crate_path out+err> /dev/null
print $"✅ ($display_name): Installed successfully"
} else if ($item.install_mode == "leptos") or ($item.install_mode | str starts-with "leptos") {
# Leptos CSR build using build-dashboard.nu script
print $" 🎨 Building Leptos WASM dashboard..."
# Call build-dashboard.nu to handle the full build (CSS + WASM)
# This script must be run from core/ directory
try {
cd core
nu ../scripts/core/build-dashboard.nu build out+err> /dev/null
cd ..
print $" ✅ Leptos WASM build completed"
} catch { |err|
cd ..
print $" ❌ Leptos WASM build failed: ($err)"
return {
success: false,
crate_name: $item.crate_name,
binary_name: $item.binary_name,
crate_path: $item.crate_path,
reason: $"Leptos build failed: ($err)"
}
}
# Deploy artifacts to public folder
print $" 📦 Deploying Leptos artifacts for ($display_name)..."
let deployment_ok = (deploy_leptos_artifacts)
if not $deployment_ok {
print $" ⚠️ Leptos artifact deployment had issues (build output may not exist yet)"
# Don't fail installation - artifacts will be available after first build
}
} else {
print $"⚠️ Unknown install_mode: ($item.install_mode), skipping"
return {
success: false,
crate_name: $item.crate_name,
binary_name: $item.binary_name,
crate_path: $item.crate_path,
reason: $"Unknown install_mode: ($item.install_mode)"
}
}
if $rm_target {
let target_dir = "target"
if ($target_dir | path exists) {
rm -r $target_dir
print $" 🧹 Cleaned up build artifacts for ($display_name)"
}
}
return {
success: true,
crate_name: $item.crate_name,
binary_name: $item.binary_name,
crate_path: $item.crate_path
}
} catch { |err|
print $"❌ ($display_name): Build failed - ($err)"
return {
success: false,
crate_name: $item.crate_name,
binary_name: $item.binary_name,
crate_path: $item.crate_path,
reason: ($err | to_string)
}
}
}
def deploy_leptos_artifacts [] {
# Deploy compiled Leptos artifacts to public directory
# This is called AFTER build-dashboard.nu has generated artifacts in core/target/site/
let home = $env.HOME
let public_dir = $"($home)/.config/syntaxis/public"
let leptos_build_dir = "core/target/site"
print " 📂 Preparing artifact deployment..."
# Create public directory if doesn't exist
try {
^mkdir -p $public_dir
} catch { |err|
print $" ❌ Failed to create public directory: ($err)"
return false
}
# Check if Leptos build artifacts exist
if not ($leptos_build_dir | path exists) {
print $" ⚠️ Leptos build artifacts not found at: ($leptos_build_dir)"
print $" 📌 This is expected if build-dashboard.nu hasn't run yet"
return false
}
# Verify artifact structure before copying
print " 🔍 Verifying artifact structure..."
mut all_artifacts_present = true
if not ("($leptos_build_dir)/index.html" | path exists) {
print $" ⚠️ index.html not found"
$all_artifacts_present = false
} else {
print $" ✅ index.html verified"
}
if not ("($leptos_build_dir)/pkg" | path exists) {
print $" ⚠️ WASM artifacts (pkg/) not found"
$all_artifacts_present = false
} else {
let wasm_files = (glob $"($leptos_build_dir)/pkg/**/*.wasm" | length)
print ($" ✅ WASM artifacts verified " + ($wasm_files | into string) + " files")
}
if not ("($leptos_build_dir)/styles/app.css" | path exists) {
print $" ⚠️ CSS file (styles/app.css) not found"
$all_artifacts_present = false
} else {
let size_bytes = (stat $"($leptos_build_dir)/styles/app.css" | get size)
let size_kb = (($size_bytes / 1024) | math round --precision 2)
print ($" ✅ CSS verified " + ($size_kb | into string) + "KB")
}
if not $all_artifacts_present {
print $" ❌ Some artifacts are missing. Cannot deploy."
return false
}
# Copy Leptos artifacts to public directory
print " 📥 Copying artifacts to ($public_dir)..."
try {
# Copy all contents of leptos_build_dir to public_dir
# Using -r for recursive, and ensuring we copy the contents, not the directory itself
^cp -r $"($leptos_build_dir)/." $"($public_dir)/"
# Verify deployment
if ("($public_dir)/index.html" | path exists) {
print $" ✅ Deployed Leptos artifacts successfully"
print $" - index.html: SPA entry point"
print $" - pkg/: WASM binaries and JS bindings"
print $" - styles/app.css: Generated CSS"
return true
} else {
print $" ❌ Deployment verification failed"
return false
}
} catch { |err|
print $" ❌ Failed to deploy Leptos artifacts: ($err)"
return false
}
}
def deploy_leptos_dashboard [] {
# Build and deploy Leptos CSR dashboard
print ""
print "🚀 Building and deploying Leptos CSR dashboard..."
let home = $env.HOME
let public_dir = $"($home)/.config/syntaxis/public"
let leptos_build_dir = "core/crates/client/target/site"
# Create public directory
^mkdir -p $public_dir
print $"📂 Created public directory: ($public_dir)"
# Build Leptos CSR (if cargo-leptos is available)
try {
print " Building Leptos CSR..."
cd core/crates/dashboard-client
cargo build --release out+err> /dev/null
cd ../../..
if ($leptos_build_dir | path exists) {
# Copy compiled site to public directory
cp -r $"($leptos_build_dir)/*" $public_dir
print $" ✅ Deployed Leptos site to ($public_dir)"
} else {
print $" ⚠️ Leptos build directory not found at ($leptos_build_dir)"
print $" Ensure cargo-leptos is installed: cargo install cargo-leptos"
}
} catch { |err|
print $" ⚠️ Leptos build skipped: ($err)"
print $" You can manually build with: cargo leptos build --release"
}
}
def backup_if_exists [path: string, archive_root: string] {
# Move existing file to timestamped archive folder if it exists
# archive_root: parent directory to contain archives/YYYY-MM-DD-HH-MM/
if ($path | path exists) {
let filename = ($path | path basename)
try {
# Create archive directory with timestamp (YYYY-MM-DD-HH-MM)
let now = (date now | format date "%Y-%m-%d-%H-%M")
let archive_dir = ($archive_root + "/archives/" + $now)
# Create archive directory if it doesn't exist
^mkdir -p $archive_dir
# Move file to archive
let backup_path = ($archive_dir + "/" + $filename)
^mv $path $backup_path
print $" ⚠️ Previous version of ($filename) exists"
print $" 📦 Archived to: archives/($now)/"
print $" Previous version preserved - you can restore if needed"
} catch { |err|
print $" ⚠️ Failed to archive ($filename): ($err)"
}
}
}
def deploy_config_for_binary [crate_name: string, config_src: string] {
# Deploy configuration from config_src (relative to project root) to ~/.config/syntaxis/
# Backs up existing configs to archives/YYYY-MM-DD-HH-MM/ before installing new ones
if ($config_src | str length) == 0 {
# No config to deploy
return
}
let config_dir = ($env.HOME + "/.config/syntaxis")
# config_src is relative to project root
let src_path = $config_src
# Ensure source exists
if not ($src_path | path exists) {
print $" ⚠️ Config source not found: ($src_path)"
return
}
try {
# Create config directory if doesn't exist
^mkdir -p $config_dir
# Copy config files from source to config directory
if ($src_path | path type) == "dir" {
# For directories, backup existing files in config_dir that come from src
let files_to_deploy = (glob $"($src_path)/*" | compact)
for file_path in $files_to_deploy {
let filename = ($file_path | path basename)
let dest_path = $"($config_dir)/($filename)"
# Backup existing file if it exists
backup_if_exists $dest_path $config_dir
}
# Copy all files from source directory
^cp -r $"($src_path)/." $"($config_dir)/" out+err> /dev/null
print $" ✅ Deployed config from ($src_path)"
} else if ($src_path | path type) == "file" {
# Copy single file
let filename = ($src_path | path basename)
let dest_path = $"($config_dir)/($filename)"
# Backup existing file if it exists
backup_if_exists $dest_path $config_dir
^cp $src_path $dest_path
print $" ✅ Deployed config: ($filename)"
}
} catch { |err|
print $" ⚠️ Failed to deploy config: ($err)"
}
}
def deploy_configurations [] {
# Create config directories and default configs
let config_dir = ($env.HOME + "/.config/syntaxis")
^mkdir -p $config_dir
^mkdir -p $"($config_dir)/public"
^mkdir -p $"($config_dir)/features"
print ""
print "📋 Deploying global configuration structure..."
# Create default main config if doesn't exist
let default_main_config = $"($config_dir)/syntaxis.toml"
if not ($default_main_config | path exists) {
let config_content = "# Syntaxis Global Configuration
# Main config file for all syntaxis applications
[server]
host = \"127.0.0.1\"
port = 8080
[api]
host = \"127.0.0.1\"
port = 8080
[database]
url = \"sqlite:///($env.HOME)/.local/share/syntaxis/syntaxis.db\"
[logging]
level = \"info\"
format = \"compact\"
"
$config_content | save $default_main_config
print $" ✅ Created: syntaxis.toml"
}
print ""
print $"📂 Configuration directories created at: ($config_dir)"
}
def create_wrapper_for_binary [binary_name: string, use_wrapper: bool, config_src: string] {
# Create wrapper script for a single binary
# Backs up existing wrapper scripts to archives/YYYY-MM-DD-HH-MM/ before installing new ones
if not $use_wrapper {
return
}
let cargo_bin = ($env.HOME + "/.cargo/bin")
let config_dir = ($env.HOME + "/.config/syntaxis")
let binary_path = ($cargo_bin + "/" + $binary_name)
let real_binary_path = ($cargo_bin + "/" + $binary_name + ".real")
# Check if binary exists
if ($binary_path | path exists) {
let display_name = $"(ansi blue)($binary_name)(ansi reset)"
try {
# Rename actual binary to .real (don't backup the binary, it's rebuilt each time)
^mv $binary_path $real_binary_path
# Create bash wrapper script that calls the NuShell wrapper
# The bash script sets NU_LIB_DIRS and calls the .nu script
let bash_wrapper = $"#!/bin/bash
# Bash wrapper for ($binary_name)
# Calls the NuShell wrapper with proper library paths
export NU_LIB_DIRS=\"\$HOME/.config/syntaxis/scripts\"
exec nu \"\$HOME/.config/syntaxis/scripts/($binary_name).nu\" \"\$@\""
$bash_wrapper | save --force $binary_path
^chmod +x $binary_path
print $" ✅ Created wrapper for ($display_name)"
print $" Location: ($binary_path)"
} catch { |err|
print $" ⚠️ Failed to create wrapper for ($display_name): ($err)"
}
}
}
def needs_wrapper [has_clap: bool, has_wasm: bool, has_leptos: bool] {
# RULE: Determine if binary needs a wrapper script
# - If HAS clap → NO wrapper (user provides args via CLI)
# - If NO clap AND NO wasm AND NO leptos → WRAPPER needed (auto-discovery)
# - If has wasm or leptos → WASM/frontend, no wrapper needed
if $has_clap {
# Has Clap: user provides arguments explicitly
return false
} else if ($has_wasm or $has_leptos) {
# WASM frontend: no CLI wrapper needed
return false
} else {
# No Clap, no WASM/Leptos: needs wrapper for auto-discovery config
return true
}
}
def register_installations [installed_binaries: list] {
# Create manifest file tracking with version and integrity info
let manifest_path = ".syntaxis/manifest.toml"
^mkdir -p ".syntaxis"
print ""
print "📊 Registering installations..."
let now = (date now | format date "%Y-%m-%d %H:%M:%S")
let home = $env.HOME
let config_dir = $"($home)/.config/syntaxis"
# Build binaries section
let binaries_toml = (
$installed_binaries
| each { |binary|
let section = $"[binaries.($binary.crate_name)]
installed = true
version = \"0.1.0\"
installed_at = \"($now)\"
"
$section
}
| str join "\n"
)
# Create comprehensive manifest
let manifest_content = $"# syntaxis Installation Manifest
# Auto-generated during installation
# Use this to track versions, verify integrity, and enable rollback
# Generated: ($now)
[installation]
created_at = \"($now)\"
last_updated = \"($now)\"
installation_root = \"(pwd)\"
ecosystem_version = \"0.1.0\"
($binaries_toml)
[configurations]
config_dir = \"($config_dir)\"
public_dir = \"($config_dir)/public\"
data_dir = \"($home)/.local/share/syntaxis\"
[leptos_dashboard]
# Leptos WASM dashboard configuration
deployed_at = \"($now)\"
artifacts_location = \"($config_dir)/public\"
wasm_target = \"wasm32-unknown-unknown\"
build_tool = \"trunk\"
css_generator = \"unocss\"
api_url_config = \"auto-detect [window.SYNTAXIS_CONFIG]\"
[environment]
SYNTAXIS_CONFIG_DIR = \"($config_dir)\"
SYNTAXIS_DATA_DIR = \"($home)/.local/share/syntaxis\"
SYNTAXIS_PUBLIC_DIR = \"($config_dir)/public\"
[verification]
all_binaries_installed = true
all_configs_deployed = true
wrappers_created = true
leptos_dashboard_deployed = true
manifest_version = \"1.0\"
"
try {
$manifest_content | save --force $manifest_path
print $" ✅ Registered installations in manifest"
print $" 📝 Manifest saved to: .syntaxis/manifest.toml"
} catch {
print $" ⚠️ Failed to create manifest"
}
}
def show_status [] {
print ""
print "📊 Installation Status"
print ""
let cargo_bin = ($env.HOME + "/.cargo/bin")
let binaries = (discover_binary_crates)
if ($binaries | length) == 0 {
print "⚠️ No binary crates found"
return
}
let status_rows = (
$binaries | each { |binary|
let bin_path = ($cargo_bin + "/" + $binary.binary_name)
let status = if ($bin_path | path exists) {
"✅ Installed"
} else {
"⚠️ Not installed"
}
{
binary: $binary.binary_name,
crate: $binary.crate_name,
status: $status,
path: $binary.crate_path,
wrapper: $binary.use_wrapper,
mode: $binary.install_mode,
config: $binary.config_src
}
}
)
print ($status_rows | table -i false | ansi strip)
print ""
print "📝 Note: Add ~/.cargo/bin to your PATH if binaries show as not installed"
print $" export PATH=\"\$HOME/.cargo/bin:\$PATH\""
print ""
}
def resolve_binary_from_action [action: string, all_binaries: list] {
# Resolve binary from action, supporting:
# 1. Full binary name: "syntaxis-cli"
# 2. Short name: "cli" (extracts last component from crate_path core/crates/cli)
# 3. Crate name: "syntaxis-cli"
let matching = (
$all_binaries | where { |b|
(($b.binary_name == $action) or
($b.crate_name == $action) or
(($b.crate_path | path basename) == $action))
}
)
return $matching
}
def list_binaries [] {
print ""
print "📦 Available Binaries (Auto-discovered)"
print ""
let binaries = (discover_binary_crates)
if ($binaries | length) == 0 {
print "⚠️ No binary crates found in workspace"
return
}
print ($binaries | table -i false | ansi strip)
#$binaries | each { |binary|
# print $" ($binary.crate_name) → ($binary.crate_path)"
#}
print ""
}
def main [
action?: string # Action: "all", "status", "list", or binary name
--rm-target # Remove target directories after build (default: false)
] {
show_logo
# Show help if no arguments or help requested
if ($action == null or $action == "help") {
print_help
return
}
# Handle status command
if ($action == "status") {
show_status
return
}
# Handle list command
if ($action == "list") {
list_binaries
return
}
# Discover available binaries
let all_binaries = (discover_binary_crates)
if ($all_binaries | length) == 0 {
print "❌ No binary crates found in workspace"
return
}
# Determine which binaries to install
let binaries_to_install = if ($action == "all") {
$all_binaries
} else {
# Find matching binary by binary_name, crate_name, or path
let matching = (resolve_binary_from_action $action $all_binaries)
if ($matching | length) == 0 {
print $"❌ Unknown binary: ($action)"
print ""
print "Available binaries:"
let binaries_list = $all_binaries
$binaries_list | each { |b|
let short_name = ($b.crate_path | path basename)
let display = $" - ($short_name) \(or ($b.binary_name), or ($b.crate_name)\)"
print $display
}
return
}
$matching
}
print ""
let binaries_count = ($binaries_to_install | length)
print $"🔨 Installing ($binaries_count) binary crate\(s\)... Remove target: ($rm_target)"
print ""
# Deploy library files first, before creating wrappers
# This ensures wrappers can import the libs when needed
print "📋 Deploying library files..."
deploy_libs $binaries_to_install
print ""
# Install each binary with immediate wrapper and config setup
# Stop on first failure
let install_result = (
$binaries_to_install | reduce {|binary, acc|
if $acc.failed {
# Already failed, skip remaining binaries
$acc
} else {
let display_name = $"(ansi blue)($binary.crate_name)(ansi reset)"
print $"📦 Step 1/3: Building ($display_name)..."
let result = (install_binary $binary $rm_target)
if $result.success {
# Build succeeded - immediately set up wrapper and config
let config_dir = ($env.HOME + "/.config/syntaxis")
let cargo_bin = ($env.HOME + "/.cargo/bin")
print $"📦 Step 2/3: Setting up wrapper and configuration..."
print $" Config Path: ($config_dir)"
print $" Wrapper Path: ($cargo_bin)"
# Create wrapper if applicable
if $binary.use_wrapper {
create_wrapper_for_binary $binary.binary_name $binary.use_wrapper $binary.config_src
}
# Deploy config if applicable
if ($binary.config_src | str length) > 0 {
deploy_config_for_binary $binary.crate_name $binary.config_src
}
print $"📦 Step 3/3: Registered ($display_name)"
print ""
{
installed: ($acc.installed | append $result)
failed: false
}
} else {
# Installation failed - stop processing
print "❌ Installation failed - stopping further installations"
print ""
{
installed: $acc.installed
failed: true
}
}
}
} -f {installed: [], failed: false}
)
let installed = $install_result.installed
let installation_failed = $install_result.failed
# Deploy additional global resources only if any binaries were installed
if ($installed | length) > 0 {
# deploy_leptos_dashboard
# Deploy default configuration (may already exist per-binary)
print ""
print "📋 Deploying global configuration..."
let config_dir = ($env.HOME + "/.config/syntaxis")
^mkdir -p $config_dir
^mkdir -p $"($config_dir)/features"
print $" ✅ Ensured config directory: ($config_dir)"
register_installations $installed
}
# Summary
print ""
print "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
let installed_count = ($installed | length)
let total_count = ($binaries_to_install | length)
print $"✨ Summary: ($installed_count)/($total_count) binaries installed"
if $installation_failed {
print "❌ Installation stopped due to failure"
} else if $installed_count == $total_count {
print "🎉 All binaries installed successfully!"
} else if $installed_count > 0 {
let failed = ($total_count - $installed_count)
print $"⚠️ ($failed) installation(s) failed"
} else {
print "❌ No binaries were installed"
}
print ""
if ($installed | length) > 0 {
print "Next steps:"
$installed | each { |binary|
print $" ($binary.crate_name) --help # Get help"
}
}
print ""
}