250 lines
7.7 KiB
Plaintext
250 lines
7.7 KiB
Plaintext
|
|
# Provider Registry System
|
||
|
|
# Dynamic provider discovery, registration, and management
|
||
|
|
|
||
|
|
use ../config/accessor.nu *
|
||
|
|
use interface.nu *
|
||
|
|
|
||
|
|
# Provider registry cache file path
|
||
|
|
def get-provider-cache-file []: nothing -> string {
|
||
|
|
let cache_dir = ($env.HOME | path join ".cache" "provisioning")
|
||
|
|
if not ($cache_dir | path exists) {
|
||
|
|
mkdir $cache_dir
|
||
|
|
}
|
||
|
|
$cache_dir | path join "provider-registry.json"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check if registry is initialized
|
||
|
|
def is-registry-initialized []: nothing -> bool {
|
||
|
|
($env.PROVIDER_REGISTRY_INITIALIZED? | default false)
|
||
|
|
}
|
||
|
|
|
||
|
|
# Mark registry as initialized
|
||
|
|
def mark-registry-initialized []: nothing -> nothing {
|
||
|
|
$env.PROVIDER_REGISTRY_INITIALIZED = true
|
||
|
|
}
|
||
|
|
|
||
|
|
# Initialize the provider registry
|
||
|
|
export def init-provider-registry []: nothing -> nothing {
|
||
|
|
if (is-registry-initialized) {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check if cache exists and is recent (less than 1 hour old)
|
||
|
|
let cache_file = (get-provider-cache-file)
|
||
|
|
if ($cache_file | path exists) {
|
||
|
|
let cache_age = ((date now) - (ls $cache_file | get 0.modified))
|
||
|
|
if ($cache_age | into int) < 3600_000_000_000 { # 1 hour in nanoseconds
|
||
|
|
# Use cached registry
|
||
|
|
mark-registry-initialized
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
print "🔄 Initializing provider registry..."
|
||
|
|
|
||
|
|
# Discover and cache providers
|
||
|
|
discover-and-register-providers
|
||
|
|
mark-registry-initialized
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get provider registry from cache or discover
|
||
|
|
def get-provider-registry []: nothing -> record {
|
||
|
|
let cache_file = (get-provider-cache-file)
|
||
|
|
if ($cache_file | path exists) {
|
||
|
|
open $cache_file
|
||
|
|
} else {
|
||
|
|
discover-providers-only
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Discover providers without full registration
|
||
|
|
def discover-providers-only []: nothing -> record {
|
||
|
|
mut registry = {}
|
||
|
|
|
||
|
|
# Get base path from config or environment
|
||
|
|
let base_path = (config-get "paths.base" ($env.PROVISIONING? | default "/Users/Akasha/project-provisioning/provisioning"))
|
||
|
|
|
||
|
|
# Core providers
|
||
|
|
let core_providers_path = ($base_path | path join "core" "nulib" "providers")
|
||
|
|
if ($core_providers_path | path exists) {
|
||
|
|
let core_providers = (discover-providers-in-directory $core_providers_path "core")
|
||
|
|
$registry = ($registry | merge $core_providers)
|
||
|
|
}
|
||
|
|
|
||
|
|
# Extension providers
|
||
|
|
let extension_providers_path = ($base_path | path join "extensions" "providers")
|
||
|
|
if ($extension_providers_path | path exists) {
|
||
|
|
let extension_providers = (discover-providers-in-directory $extension_providers_path "extension")
|
||
|
|
$registry = ($registry | merge $extension_providers)
|
||
|
|
}
|
||
|
|
|
||
|
|
$registry
|
||
|
|
}
|
||
|
|
|
||
|
|
# Discover and register all providers
|
||
|
|
def discover-and-register-providers []: nothing -> nothing {
|
||
|
|
let registry = (discover-providers-only)
|
||
|
|
|
||
|
|
# Save to cache
|
||
|
|
let cache_file = (get-provider-cache-file)
|
||
|
|
$registry | to json | save --force $cache_file
|
||
|
|
|
||
|
|
print $"✅ Discovered ($registry | columns | length) providers"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Discover providers in a specific directory
|
||
|
|
def discover-providers-in-directory [base_path: string, provider_type: string]: nothing -> record {
|
||
|
|
mut providers = {}
|
||
|
|
|
||
|
|
if not ($base_path | path exists) {
|
||
|
|
return $providers
|
||
|
|
}
|
||
|
|
|
||
|
|
# Look for provider.nu files in subdirectories
|
||
|
|
let provider_dirs = (ls $base_path | where type == dir | get name)
|
||
|
|
|
||
|
|
for dir in $provider_dirs {
|
||
|
|
let provider_file = ($dir | path join "provider.nu")
|
||
|
|
if ($provider_file | path exists) {
|
||
|
|
let provider_name = ($dir | path basename)
|
||
|
|
|
||
|
|
# Check if provider has metadata function (just test it's valid)
|
||
|
|
# We don't parse the metadata here, just verify the provider loads
|
||
|
|
let has_metadata = (do {
|
||
|
|
nu -c $"use ($provider_file) *; get-provider-metadata | ignore"
|
||
|
|
} | complete | get exit_code) == 0
|
||
|
|
|
||
|
|
if $has_metadata {
|
||
|
|
let provider_info = {
|
||
|
|
name: $provider_name
|
||
|
|
type: $provider_type
|
||
|
|
path: $dir
|
||
|
|
entry_point: $provider_file
|
||
|
|
available: true
|
||
|
|
loaded: false
|
||
|
|
last_discovered: (date now)
|
||
|
|
}
|
||
|
|
|
||
|
|
$providers = ($providers | insert $provider_name $provider_info)
|
||
|
|
print $" 📦 Found ($provider_type) provider: ($provider_name)"
|
||
|
|
} else {
|
||
|
|
print $" ⚠️ Invalid provider: ($provider_name)"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$providers
|
||
|
|
}
|
||
|
|
|
||
|
|
# List all available providers
|
||
|
|
export def list-providers [
|
||
|
|
--available-only # Only show available providers
|
||
|
|
--verbose # Show detailed information
|
||
|
|
]: nothing -> table {
|
||
|
|
if not (is-registry-initialized) {
|
||
|
|
init-provider-registry | ignore
|
||
|
|
}
|
||
|
|
|
||
|
|
let registry = (get-provider-registry)
|
||
|
|
let providers = ($registry | transpose name details)
|
||
|
|
|
||
|
|
let filtered = if $available_only {
|
||
|
|
$providers | where {|p| $p.details.available == true}
|
||
|
|
} else {
|
||
|
|
$providers
|
||
|
|
}
|
||
|
|
|
||
|
|
if $verbose {
|
||
|
|
$filtered | select name details.type details.available details.loaded details.path details.last_discovered
|
||
|
|
} else {
|
||
|
|
$filtered | select name details.type details.available details.loaded
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check if a provider is available
|
||
|
|
export def is-provider-available [provider_name: string]: nothing -> bool {
|
||
|
|
if not (is-registry-initialized) {
|
||
|
|
init-provider-registry | ignore
|
||
|
|
}
|
||
|
|
|
||
|
|
let registry = (get-provider-registry)
|
||
|
|
|
||
|
|
if ($provider_name in ($registry | columns)) {
|
||
|
|
let provider = ($registry | get $provider_name)
|
||
|
|
$provider.available
|
||
|
|
} else {
|
||
|
|
false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get provider entry information
|
||
|
|
export def get-provider-entry [provider_name: string]: nothing -> record {
|
||
|
|
if not (is-registry-initialized) {
|
||
|
|
init-provider-registry | ignore
|
||
|
|
}
|
||
|
|
|
||
|
|
let registry = (get-provider-registry)
|
||
|
|
|
||
|
|
if ($provider_name in ($registry | columns)) {
|
||
|
|
$registry | get $provider_name
|
||
|
|
} else {
|
||
|
|
error make { msg: $"Provider ($provider_name) not found in registry" }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get provider registry statistics
|
||
|
|
export def get-provider-stats []: nothing -> record {
|
||
|
|
if not (is-registry-initialized) {
|
||
|
|
init-provider-registry | ignore
|
||
|
|
}
|
||
|
|
|
||
|
|
let registry = (get-provider-registry)
|
||
|
|
let providers = ($registry | transpose name details)
|
||
|
|
|
||
|
|
{
|
||
|
|
total_providers: ($providers | length)
|
||
|
|
available_providers: ($providers | where {|p| $p.details.available == true} | length)
|
||
|
|
core_providers: ($providers | where {|p| $p.details.type == "core"} | length)
|
||
|
|
extension_providers: ($providers | where {|p| $p.details.type == "extension"} | length)
|
||
|
|
loaded_providers: ($providers | where {|p| $p.details.loaded == true} | length)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get capabilities for a specific provider
|
||
|
|
export def get-provider-capabilities-for [provider_name: string]: nothing -> record {
|
||
|
|
if not (is-provider-available $provider_name) {
|
||
|
|
return {}
|
||
|
|
}
|
||
|
|
|
||
|
|
let provider_entry = (get-provider-entry $provider_name)
|
||
|
|
|
||
|
|
let metadata_cmd = $"nu -c \"use ($provider_entry.entry_point) *; get-provider-metadata\""
|
||
|
|
let result = (nu -c $metadata_cmd | complete)
|
||
|
|
|
||
|
|
if $result.exit_code == 0 {
|
||
|
|
let metadata = ($result.stdout | from json)
|
||
|
|
$metadata.capabilities? | default {}
|
||
|
|
} else {
|
||
|
|
{}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Refresh the provider registry
|
||
|
|
export def refresh-provider-registry []: nothing -> nothing {
|
||
|
|
# Clear cache
|
||
|
|
let cache_file = (get-provider-cache-file)
|
||
|
|
if ($cache_file | path exists) {
|
||
|
|
rm $cache_file
|
||
|
|
}
|
||
|
|
|
||
|
|
# Reset initialization flag
|
||
|
|
$env.PROVIDER_REGISTRY_INITIALIZED = false
|
||
|
|
|
||
|
|
# Reinitialize
|
||
|
|
init-provider-registry | ignore
|
||
|
|
}
|
||
|
|
|
||
|
|
# Export environment setup
|
||
|
|
export-env {
|
||
|
|
$env.PROVIDER_REGISTRY_INITIALIZED = false
|
||
|
|
}
|