524 lines
17 KiB
Text
524 lines
17 KiB
Text
|
|
# Platform Service Manager - Service management for deployment
|
||
|
|
# Handles loading deployment configuration and service management
|
||
|
|
|
||
|
|
use tools/nickel/process.nu [ncl-eval ncl-eval-soft]
|
||
|
|
use platform/user/config.nu [get-active-workspace-details get-platform-config-dir]
|
||
|
|
|
||
|
|
# Normalize service name: strip "provisioning-" or "provisioning_" prefix if present
|
||
|
|
# Returns the normalized name (e.g., "provisioning_daemon" → "daemon")
|
||
|
|
export def normalize-service-name [service_name: string] {
|
||
|
|
if ($service_name | str starts-with "provisioning-") {
|
||
|
|
$service_name | str replace "provisioning-" ""
|
||
|
|
} else if ($service_name | str starts-with "provisioning_") {
|
||
|
|
$service_name | str replace "provisioning_" ""
|
||
|
|
} else {
|
||
|
|
$service_name
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Load deployment mode configuration from Nickel
|
||
|
|
export def load-deployment-mode [] {
|
||
|
|
# Prefer explicit env override; otherwise the OS-aware platform dir.
|
||
|
|
let possible_paths = [
|
||
|
|
($env.PROVISIONING_USER_PLATFORM? | default null),
|
||
|
|
(get-platform-config-dir),
|
||
|
|
]
|
||
|
|
|
||
|
|
let config_file = (
|
||
|
|
$possible_paths
|
||
|
|
| where { |p| $p != null }
|
||
|
|
| each { |p| $p | path expand | path join "deployment-mode.ncl" }
|
||
|
|
| where { |p| $p | path exists }
|
||
|
|
| get 0?
|
||
|
|
)
|
||
|
|
|
||
|
|
if ($config_file == null) {
|
||
|
|
error make {msg: "Deployment mode file not found in any of the expected locations"}
|
||
|
|
}
|
||
|
|
|
||
|
|
let import_path = ($env.PROVISIONING? | default "")
|
||
|
|
let import_paths = if ($import_path | is-not-empty) { [$import_path] } else { [] }
|
||
|
|
ncl-eval $config_file $import_paths
|
||
|
|
}
|
||
|
|
|
||
|
|
# Load individual service configuration
|
||
|
|
export def load-service-config [service_name: string] {
|
||
|
|
# Prefer explicit env override; otherwise the OS-aware platform dir.
|
||
|
|
let possible_bases = [
|
||
|
|
($env.PROVISIONING_USER_PLATFORM? | default null),
|
||
|
|
(get-platform-config-dir),
|
||
|
|
]
|
||
|
|
|
||
|
|
# Try to find the config file
|
||
|
|
let config_file = (
|
||
|
|
$possible_bases
|
||
|
|
| where { |b| $b != null }
|
||
|
|
| each { |base|
|
||
|
|
# Try both the underscore and dash versions
|
||
|
|
let base_expanded = ($base | path expand)
|
||
|
|
let path1 = ($base_expanded | path join "config" ($"($service_name).ncl"))
|
||
|
|
let path2 = ($base_expanded | path join "config" ($"($service_name | str replace "_" "-").ncl"))
|
||
|
|
|
||
|
|
if ($path1 | path exists) {
|
||
|
|
$path1
|
||
|
|
} else if ($path2 | path exists) {
|
||
|
|
$path2
|
||
|
|
} else {
|
||
|
|
null
|
||
|
|
}
|
||
|
|
}
|
||
|
|
| where { |p| $p != null }
|
||
|
|
| get 0?
|
||
|
|
)
|
||
|
|
|
||
|
|
if ($config_file == null) {
|
||
|
|
return null
|
||
|
|
}
|
||
|
|
|
||
|
|
ncl-eval-soft $config_file [] null
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get the port for a service from its per-service NCL config file.
|
||
|
|
export def get-service-port [service_name: string] {
|
||
|
|
let config = (load-service-config $service_name)
|
||
|
|
|
||
|
|
if ($config == null) {
|
||
|
|
return "?"
|
||
|
|
}
|
||
|
|
|
||
|
|
let service_key = $service_name | str replace "-" "_"
|
||
|
|
|
||
|
|
if ($config | get --optional $service_key) != null {
|
||
|
|
let service_config = ($config | get $service_key)
|
||
|
|
|
||
|
|
if ($service_config | get --optional "server") != null {
|
||
|
|
if ($service_config.server | get --optional "port") != null {
|
||
|
|
return ($service_config.server.port | into string)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if ($service_config | get --optional "build") != null {
|
||
|
|
if ($service_config.build | get --optional "port") != null {
|
||
|
|
return ($service_config.build.port | into string)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if ($service_config | get --optional "http") != null {
|
||
|
|
if ($service_config.http | get --optional "port") != null {
|
||
|
|
return ($service_config.http.port | into string)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if ($service_config | get --optional "port") != null {
|
||
|
|
return ($service_config.port | into string)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
"?"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Start required services based on deployment configuration
|
||
|
|
export def start-required-services [] {
|
||
|
|
let deployment = (load-deployment-mode)
|
||
|
|
|
||
|
|
# Get enabled services from deployment config
|
||
|
|
let services = $deployment.services
|
||
|
|
let all_service_names = ($services | columns)
|
||
|
|
|
||
|
|
# Filter to enabled services
|
||
|
|
let enabled_services = (
|
||
|
|
$all_service_names
|
||
|
|
| where {|name|
|
||
|
|
let config = ($services | get $name)
|
||
|
|
($config | get --optional "enabled" | default false)
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
if ($enabled_services | length) == 0 {
|
||
|
|
print "⚠ No services enabled in deployment-mode.ncl"
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get current running processes once
|
||
|
|
let running_processes = (^ps aux)
|
||
|
|
|
||
|
|
# Start each enabled service
|
||
|
|
for service_name in $enabled_services {
|
||
|
|
let port = (get-service-port $service_name)
|
||
|
|
let normalized_name = (normalize-service-name $service_name)
|
||
|
|
let binary_name = $"provisioning-($normalized_name | str replace "_" "-")"
|
||
|
|
let is_running = ($running_processes | str contains $binary_name)
|
||
|
|
|
||
|
|
# Check if binary exists
|
||
|
|
let home = ($env.HOME? | default "~" | path expand)
|
||
|
|
let binary_path = ($home | path join ".local/bin" $binary_name)
|
||
|
|
|
||
|
|
if not ($binary_path | path exists) {
|
||
|
|
print $"✗ ($service_name) binary not found"
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
# If already running, just report it
|
||
|
|
if $is_running {
|
||
|
|
let status_msg = $"((ansi green))started((ansi reset))"
|
||
|
|
print $"✓ ($service_name) on port ($port) — ($status_msg)"
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
# Start in background
|
||
|
|
print $"→ Starting ($service_name)..."
|
||
|
|
|
||
|
|
let log_dir = ($home | path join ".provisioning/logs")
|
||
|
|
(do { mkdir ($log_dir) } | ignore)
|
||
|
|
let log_file = ($log_dir | path join $"($service_name).log")
|
||
|
|
|
||
|
|
# Set environment variables for service
|
||
|
|
let platform_path = (get-platform-config-dir)
|
||
|
|
let provisioning_path = ($home | path join ".local/bin/provisioning")
|
||
|
|
|
||
|
|
# Build start command (only orchestrator accepts --provisioning-path)
|
||
|
|
let start_cmd = if ($normalized_name == "orchestrator") {
|
||
|
|
$"nohup env PROVISIONING_USER_PLATFORM=\"($platform_path)\" PROVISIONING_CONFIG_DIR=\"($platform_path)\" ($binary_path) --provisioning-path \"($provisioning_path)\" >>\"($log_file)\" 2>&1 &"
|
||
|
|
} else {
|
||
|
|
$"nohup env PROVISIONING_USER_PLATFORM=\"($platform_path)\" PROVISIONING_CONFIG_DIR=\"($platform_path)\" ($binary_path) >>\"($log_file)\" 2>&1 &"
|
||
|
|
}
|
||
|
|
|
||
|
|
(^sh -c $start_cmd | ignore)
|
||
|
|
sleep 2sec
|
||
|
|
|
||
|
|
let started_msg = $"((ansi green))started((ansi reset))"
|
||
|
|
print $"✓ ($service_name) on port ($port) — ($started_msg)"
|
||
|
|
}
|
||
|
|
|
||
|
|
# ncl-sync: Nickel config cache daemon — always started, independent of deployment mode.
|
||
|
|
ncl-sync-start
|
||
|
|
|
||
|
|
print ""
|
||
|
|
}
|
||
|
|
|
||
|
|
# Start specific services by name
|
||
|
|
# Usage: start-services ["orchestrator", "vault_service"] or ["orchestrator,vault_service"]
|
||
|
|
export def start-services [service_list: list<string>] {
|
||
|
|
# Parse service names (handle comma-separated strings)
|
||
|
|
let services = (
|
||
|
|
$service_list
|
||
|
|
| each { |item| $item | split row "," | each { |s| $s | str trim } }
|
||
|
|
| flatten
|
||
|
|
| where { |s| ($s | is-not-empty) }
|
||
|
|
)
|
||
|
|
|
||
|
|
if ($services | length) == 0 {
|
||
|
|
print "⚠ No services specified"
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
# Start each service
|
||
|
|
for service_name in $services {
|
||
|
|
let normalized_name = (normalize-service-name $service_name)
|
||
|
|
let port = (get-service-port $normalized_name)
|
||
|
|
let binary_name = $"provisioning-($normalized_name | str replace "_" "-")"
|
||
|
|
let is_running = ((^pgrep -f $"[/]($binary_name)$" | complete).exit_code == 0)
|
||
|
|
|
||
|
|
# Check if binary exists
|
||
|
|
let home = ($env.HOME? | default "~" | path expand)
|
||
|
|
let binary_path = ($home | path join ".local/bin" $binary_name)
|
||
|
|
|
||
|
|
if not ($binary_path | path exists) {
|
||
|
|
print $"✗ ($service_name) binary not found"
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
# If already running, just report it
|
||
|
|
if $is_running {
|
||
|
|
let status_msg = $"((ansi green))started((ansi reset))"
|
||
|
|
print $"✓ ($service_name) on port ($port) — ($status_msg)"
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
# Start in background
|
||
|
|
print $"→ Starting ($service_name)..."
|
||
|
|
|
||
|
|
let log_dir = ($home | path join ".provisioning/logs")
|
||
|
|
(do { mkdir ($log_dir) } | ignore)
|
||
|
|
let log_file = ($log_dir | path join $"($service_name).log")
|
||
|
|
|
||
|
|
# Set environment variables for service
|
||
|
|
let platform_path = (get-platform-config-dir)
|
||
|
|
let provisioning_path = ($home | path join ".local/bin/provisioning")
|
||
|
|
|
||
|
|
# Build start command (only orchestrator accepts --provisioning-path)
|
||
|
|
let start_cmd = if ($normalized_name == "orchestrator") {
|
||
|
|
$"nohup env PROVISIONING_USER_PLATFORM=\"($platform_path)\" PROVISIONING_CONFIG_DIR=\"($platform_path)\" ($binary_path) --provisioning-path \"($provisioning_path)\" >>\"($log_file)\" 2>&1 &"
|
||
|
|
} else {
|
||
|
|
$"nohup env PROVISIONING_USER_PLATFORM=\"($platform_path)\" PROVISIONING_CONFIG_DIR=\"($platform_path)\" ($binary_path) >>\"($log_file)\" 2>&1 &"
|
||
|
|
}
|
||
|
|
|
||
|
|
(^sh -c $start_cmd | ignore)
|
||
|
|
sleep 2sec
|
||
|
|
|
||
|
|
let started_msg = $"((ansi green))started((ansi reset))"
|
||
|
|
print $"✓ ($service_name) on port ($port) — ($started_msg)"
|
||
|
|
}
|
||
|
|
|
||
|
|
ncl-sync-start
|
||
|
|
|
||
|
|
print ""
|
||
|
|
}
|
||
|
|
|
||
|
|
# Stop specific services by name
|
||
|
|
# Usage: stop-services ["orchestrator", "vault_service"] or ["orchestrator,vault_service"]
|
||
|
|
export def stop-services [service_list: list<string>] {
|
||
|
|
# Parse service names (handle comma-separated strings)
|
||
|
|
let services = (
|
||
|
|
$service_list
|
||
|
|
| each { |item| $item | split row "," | each { |s| $s | str trim } }
|
||
|
|
| flatten
|
||
|
|
| where { |s| ($s | is-not-empty) }
|
||
|
|
)
|
||
|
|
|
||
|
|
if ($services | length) == 0 {
|
||
|
|
print "⚠ No services specified"
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
# Stop each service
|
||
|
|
for service_name in $services {
|
||
|
|
# Normalize service name: strip "provisioning-" or "provisioning_" prefix if present
|
||
|
|
let normalized_name = (
|
||
|
|
if ($service_name | str starts-with "provisioning-") {
|
||
|
|
$service_name | str replace "provisioning-" ""
|
||
|
|
} else if ($service_name | str starts-with "provisioning_") {
|
||
|
|
$service_name | str replace "provisioning_" ""
|
||
|
|
} else {
|
||
|
|
$service_name
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
let port = (get-service-port $normalized_name)
|
||
|
|
let binary_name = $"provisioning-($normalized_name | str replace "_" "-")"
|
||
|
|
let is_running = ((^pgrep -f $"[/]($binary_name)$" | complete).exit_code == 0)
|
||
|
|
|
||
|
|
if $is_running {
|
||
|
|
(^sh -c $"pkill -f '($binary_name)' 2>/dev/null || true") | ignore
|
||
|
|
sleep 500ms
|
||
|
|
let stopped_msg = $"((ansi red))stopped((ansi reset))"
|
||
|
|
print $"✓ ($service_name) on port ($port) — ($stopped_msg)"
|
||
|
|
} else {
|
||
|
|
let stopped_msg = $"((ansi red))already stopped((ansi reset))"
|
||
|
|
print $"✓ ($service_name) on port ($port) — ($stopped_msg)"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
print ""
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check if a port is listening (health check for external services)
|
||
|
|
export def is-port-listening [port: number] {
|
||
|
|
let uname_result = (do { ^uname -s } | complete)
|
||
|
|
let os_type = (if $uname_result.exit_code == 0 { $uname_result.stdout | str trim } else { "Linux" })
|
||
|
|
|
||
|
|
if $os_type == "Darwin" {
|
||
|
|
# macOS: use lsof to check listening ports
|
||
|
|
# Pattern matches both "*:PORT" and "127.0.0.1:PORT" formats
|
||
|
|
let check = (do { ^lsof -i -P -n } | complete)
|
||
|
|
if $check.exit_code == 0 {
|
||
|
|
let port_str = $"($port)"
|
||
|
|
$check.stdout | str contains $"($port_str)" | if $in { true } else { false }
|
||
|
|
} else {
|
||
|
|
false
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
# Linux: use netstat to check listening ports
|
||
|
|
let check = (do { ^netstat -tuln } | complete)
|
||
|
|
if $check.exit_code == 0 {
|
||
|
|
$check.stdout | str contains $":$port"
|
||
|
|
} else {
|
||
|
|
false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get external services from user configuration file
|
||
|
|
export def get-external-services [] {
|
||
|
|
# Prefer explicit env override; otherwise the OS-aware platform dir.
|
||
|
|
let possible_bases = [
|
||
|
|
($env.PROVISIONING_USER_PLATFORM? | default null),
|
||
|
|
(get-platform-config-dir),
|
||
|
|
]
|
||
|
|
|
||
|
|
# Try to find the external services config file
|
||
|
|
let external_services_file = (
|
||
|
|
$possible_bases
|
||
|
|
| where { |b| $b != null }
|
||
|
|
| each { |base| ($base | path expand | path join "config/external-services.ncl") }
|
||
|
|
| where { |p| $p | path exists }
|
||
|
|
| get 0?
|
||
|
|
)
|
||
|
|
|
||
|
|
if ($external_services_file == null) {
|
||
|
|
return []
|
||
|
|
}
|
||
|
|
|
||
|
|
ncl-eval-soft $external_services_file [] [] | default []
|
||
|
|
}
|
||
|
|
|
||
|
|
# Start nats-server as a child process for solo mode.
|
||
|
|
# Requires nats-server to be in PATH.
|
||
|
|
# Returns a record with {pid, port, jetstream_dir} on success.
|
||
|
|
export def nats_start [config: record]: nothing -> record {
|
||
|
|
let port = ($config.port? | default 4222)
|
||
|
|
let data_dir = ($env.HOME | path join ".local/share/provisioning/nats")
|
||
|
|
let js_dir = ($config.jetstream_store_dir? | default $data_dir)
|
||
|
|
|
||
|
|
let mk_result = (do { ^mkdir -p $js_dir } | complete)
|
||
|
|
if ($mk_result.exit_code != 0) {
|
||
|
|
error make {msg: $"Failed to create NATS data dir ($js_dir): ($mk_result.stderr)"}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Spawn nats-server in background — nohup keeps it alive after this shell exits
|
||
|
|
let cmd = $"nohup nats-server -js -sd ($js_dir) -p ($port) >/dev/null 2>&1 &"
|
||
|
|
let start_result = (do { ^sh -c $cmd } | complete)
|
||
|
|
if ($start_result.exit_code != 0) {
|
||
|
|
error make {msg: $"nats-server failed to start: ($start_result.stderr)"}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Poll for readiness — up to 10 seconds in 500ms increments
|
||
|
|
let ready = (
|
||
|
|
1..20
|
||
|
|
| each { |_i|
|
||
|
|
sleep 500ms
|
||
|
|
(nats_health {port: $port})
|
||
|
|
}
|
||
|
|
| where { |r| $r }
|
||
|
|
| length
|
||
|
|
| $in > 0
|
||
|
|
)
|
||
|
|
|
||
|
|
if (not $ready) {
|
||
|
|
error make {msg: "nats-server did not become ready within 10 seconds"}
|
||
|
|
}
|
||
|
|
|
||
|
|
let pid_result = (do { ^pgrep -f $"nats-server" } | complete)
|
||
|
|
let pid = (if ($pid_result.exit_code == 0) { $pid_result.stdout | lines | get 0? | default "0" | into int } else { 0 })
|
||
|
|
|
||
|
|
{pid: $pid, port: $port, jetstream_dir: $js_dir}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Stop the nats-server process.
|
||
|
|
export def nats_stop [config: record]: nothing -> nothing {
|
||
|
|
let port = ($config.port? | default 4222)
|
||
|
|
let kill_result = (do { ^pkill -f "nats-server" } | complete)
|
||
|
|
if ($kill_result.exit_code != 0) {
|
||
|
|
print $"Warning: nats-server on port ($port) was not running or could not be stopped"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check if nats-server is accepting TCP connections on the configured port.
|
||
|
|
# Returns true if healthy, false otherwise.
|
||
|
|
export def nats_health [config: record]: nothing -> bool {
|
||
|
|
let port = ($config.port? | default 4222)
|
||
|
|
let check = (do { ^nc -z -w 1 127.0.0.1 $port } | complete)
|
||
|
|
$check.exit_code == 0
|
||
|
|
}
|
||
|
|
|
||
|
|
# ============================================================================
|
||
|
|
# ncl-sync daemon management
|
||
|
|
# ============================================================================
|
||
|
|
|
||
|
|
def ncl-sync-cache-dir []: nothing -> string {
|
||
|
|
if ($env.NCL_CACHE_DIR? | is-not-empty) { return $env.NCL_CACHE_DIR }
|
||
|
|
# Walk up from PWD to find workspace root
|
||
|
|
let pwd = $env.PWD
|
||
|
|
let ws_pwd = if ($pwd | path join "infra" | path exists) or ($pwd | path join "config" "provisioning.ncl" | path exists) or ($pwd | path join ".ontology" | path exists) {
|
||
|
|
$pwd
|
||
|
|
} else { "" }
|
||
|
|
if ($ws_pwd | is-not-empty) { return ($ws_pwd | path join ".ncl-cache") }
|
||
|
|
# Fallback to active workspace from user_config
|
||
|
|
let details = (get-active-workspace-details)
|
||
|
|
if ($details | is-not-empty) and ($details | get -o path | is-not-empty) {
|
||
|
|
return ($details.path | path join ".ncl-cache")
|
||
|
|
}
|
||
|
|
let home = ($env.HOME? | default "~" | path expand)
|
||
|
|
$home | path join ".cache" "provisioning" "config-cache"
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def ncl-sync-bin []: nothing -> string {
|
||
|
|
let home = ($env.HOME? | default "~" | path expand)
|
||
|
|
$home | path join ".local" "bin" "provisioning-ncl-sync"
|
||
|
|
}
|
||
|
|
|
||
|
|
def ncl-sync-running []: nothing -> bool {
|
||
|
|
(do { ^ps aux } | complete).stdout | str contains "provisioning-ncl-sync"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check that a path has workspace markers (infra/, config/provisioning.ncl, or .ontology/).
|
||
|
|
def is-workspace-dir [path: string]: nothing -> bool {
|
||
|
|
if ($path | is-empty) or (not ($path | path exists)) { return false }
|
||
|
|
let has_infra = ($path | path join "infra" | path exists)
|
||
|
|
let has_config = ($path | path join "config" "provisioning.ncl" | path exists)
|
||
|
|
let has_onto = ($path | path join ".ontology" | path exists)
|
||
|
|
$has_infra or $has_config or $has_onto
|
||
|
|
}
|
||
|
|
|
||
|
|
# Walk up from `path` until a workspace root is found or we reach filesystem root.
|
||
|
|
def find-workspace-up [path: string]: nothing -> string {
|
||
|
|
if ($path | is-empty) or $path == "/" { return "" }
|
||
|
|
if (is-workspace-dir $path) { return $path }
|
||
|
|
let parent = ($path | path dirname)
|
||
|
|
if $parent == $path { return "" }
|
||
|
|
find-workspace-up $parent
|
||
|
|
}
|
||
|
|
|
||
|
|
# Start the ncl-sync daemon if not already running.
|
||
|
|
# Workspace resolution priority:
|
||
|
|
# 1. $NCL_CACHE_DIR's parent (explicit override)
|
||
|
|
# 2. Walk up from PWD until a workspace root is found
|
||
|
|
# 3. get-active-workspace-details from user_config.yaml (if it's a valid workspace path)
|
||
|
|
# 4. skip (avoid watching HOME or random dirs)
|
||
|
|
export def ncl-sync-start []: nothing -> nothing {
|
||
|
|
if (ncl-sync-running) { return }
|
||
|
|
let bin = (ncl-sync-bin)
|
||
|
|
if not ($bin | path exists) { return }
|
||
|
|
|
||
|
|
let from_pwd = (find-workspace-up $env.PWD)
|
||
|
|
let details = (get-active-workspace-details)
|
||
|
|
let from_config = if ($details | is-not-empty) and ($details | get -o path | is-not-empty) {
|
||
|
|
$details.path
|
||
|
|
} else { "" }
|
||
|
|
|
||
|
|
let ws_path = if ($from_pwd | is-not-empty) {
|
||
|
|
$from_pwd
|
||
|
|
} else if (is-workspace-dir $from_config) {
|
||
|
|
$from_config
|
||
|
|
} else {
|
||
|
|
""
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($ws_path | is-empty) {
|
||
|
|
print "→ ncl-sync: no workspace detected in PWD tree or user_config — skipping"
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
let home = ($env.HOME? | default "~" | path expand)
|
||
|
|
let log_dir = ($home | path join ".provisioning" "logs")
|
||
|
|
(do { mkdir $log_dir } | ignore)
|
||
|
|
let log_file = ($log_dir | path join "ncl-sync.log")
|
||
|
|
|
||
|
|
let cmd = $"nohup ($bin) daemon --workspace \"($ws_path)\" >>\"($log_file)\" 2>&1 &"
|
||
|
|
(^sh -c $cmd | ignore)
|
||
|
|
sleep 500ms
|
||
|
|
print $"→ ncl-sync started \(workspace: ($ws_path)\)"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Stop all ncl-sync daemon instances.
|
||
|
|
export def ncl-sync-stop []: nothing -> nothing {
|
||
|
|
(do { ^pkill -f "provisioning-ncl-sync" } | complete | ignore)
|
||
|
|
}
|
||
|
|
|
||
|
|
# Status record for ncl-sync daemon.
|
||
|
|
export def ncl-sync-status []: nothing -> record {
|
||
|
|
let running = (ncl-sync-running)
|
||
|
|
{
|
||
|
|
service: "ncl-sync",
|
||
|
|
running: $running,
|
||
|
|
}
|
||
|
|
}
|