nip/src/nimpak/variant_domains.nim

283 lines
8.7 KiB
Nim

# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## variant_domains.nim
## Semantic domain definitions for NIP variant system
## Defines 9 orthogonal domains with typed constraints
import std/tables
import variant_types
# #############################################################################
# Semantic Domain Definitions
# #############################################################################
proc initSemanticDomains*(): Table[string, FlagDomain] =
## Initialize the 9 semantic domains with their constraints
result = initTable[string, FlagDomain]()
# 1. Init System Domain
result["init"] = FlagDomain(
name: "init",
description: "Init system selection",
flagType: ftChoice,
exclusive: true,
options: @["systemd", "dinit", "openrc", "runit", "s6"],
default: "dinit",
compilerFlagRules: initTable[string, CompilerFlagRule]()
)
# 2. Runtime Features Domain
result["runtime"] = FlagDomain(
name: "runtime",
description: "Core runtime features",
flagType: ftSet,
exclusive: false,
options: @["ssl", "http3", "zstd", "ipv6", "doc", "dbus", "cuda", "rocm",
"onnx", "tensorrt", "steam", "wine", "proton"],
default: "",
compilerFlagRules: initTable[string, CompilerFlagRule]()
)
# 3. Graphics Domain
result["graphics"] = FlagDomain(
name: "graphics",
description: "Display server and GPU API",
flagType: ftChoice,
exclusive: true,
options: @["none", "X", "wayland", "vulkan", "opengl", "mesa"],
default: "none",
compilerFlagRules: initTable[string, CompilerFlagRule]()
)
# 4. Audio Domain
result["audio"] = FlagDomain(
name: "audio",
description: "Sound server selection",
flagType: ftChoice,
exclusive: true,
options: @["none", "pipewire", "pulseaudio", "alsa", "jack"],
default: "pipewire",
compilerFlagRules: initTable[string, CompilerFlagRule]()
)
# 5. Security Domain
result["security"] = FlagDomain(
name: "security",
description: "Security hardening",
flagType: ftSet,
exclusive: false,
options: @["pie", "relro", "hardened", "fortify", "stack-protector"],
default: "",
compilerFlagRules: initTable[string, CompilerFlagRule]()
)
# 6. Optimization Domain
result["optimization"] = FlagDomain(
name: "optimization",
description: "Build optimizations",
flagType: ftSet,
exclusive: false,
options: @["lto", "pgo", "march-native", "debug", "strip"],
default: "",
compilerFlagRules: initTable[string, CompilerFlagRule]()
)
# 7. Integration Domain
result["integration"] = FlagDomain(
name: "integration",
description: "System interfaces",
flagType: ftSet,
exclusive: false,
options: @["docker", "podman", "nipcells", "libvirt", "nexus-api",
"nexus-security", "nexus-monitor"],
default: "",
compilerFlagRules: initTable[string, CompilerFlagRule]()
)
# 8. Network Domain
result["network"] = FlagDomain(
name: "network",
description: "Networking stack",
flagType: ftSet,
exclusive: false,
options: @["ipv6", "wireguard", "zerotier", "mesh", "p2p", "ipfs"],
default: "",
compilerFlagRules: initTable[string, CompilerFlagRule]()
)
# 9. Developer Domain
result["developer"] = FlagDomain(
name: "developer",
description: "Development tooling",
flagType: ftSet,
exclusive: false,
options: @["debugger", "profiler", "lsp", "repl", "hot-reload", "sanitizer"],
default: "",
compilerFlagRules: initTable[string, CompilerFlagRule]()
)
# Global constant for semantic domains
const SEMANTIC_DOMAINS* = initSemanticDomains()
# #############################################################################
# Domain Query Functions
# #############################################################################
proc getDomain*(name: string): FlagDomain =
## Get a domain by name, raises KeyError if not found
result = SEMANTIC_DOMAINS[name]
proc hasDomain*(name: string): bool =
## Check if a domain exists
result = SEMANTIC_DOMAINS.hasKey(name)
proc getAllDomainNames*(): seq[string] =
## Get all domain names
result = @[]
for name in SEMANTIC_DOMAINS.keys:
result.add(name)
proc isValidDomainValue*(domain: string, value: string): bool =
## Check if a value is valid for a domain
if not hasDomain(domain):
return false
let domainDef = SEMANTIC_DOMAINS[domain]
result = value in domainDef.options
proc getDomainOptions*(domain: string): seq[string] =
## Get all valid options for a domain
if not hasDomain(domain):
return @[]
result = SEMANTIC_DOMAINS[domain].options
proc getDomainType*(domain: string): FlagType =
## Get the flag type for a domain
if not hasDomain(domain):
raise newException(KeyError, "Unknown domain: " & domain)
result = SEMANTIC_DOMAINS[domain].flagType
proc isExclusiveDomain*(domain: string): bool =
## Check if a domain is exclusive (only one value allowed)
if not hasDomain(domain):
return false
result = SEMANTIC_DOMAINS[domain].exclusive
# #############################################################################
# Legacy Category Migration
# #############################################################################
proc initLegacyCategoryMap*(): Table[string, string] =
## Initialize mapping from legacy 16 categories to new 9 domains
result = initTable[string, string]()
# Eliminated categories → New domains
result["gui"] = "graphics"
result["gaming"] = "graphics" # vulkan, opengl → graphics; steam → runtime
result["container"] = "integration"
result["virtualization"] = "integration"
result["mesh"] = "network"
result["ai-ml"] = "runtime" # cuda, rocm → runtime
result["nexus-fleet"] = "profile" # Becomes a profile, not a domain
result["nexus-bootstrap"] = "build-mode" # Build-time, not runtime
result["nexus-integration"] = "integration"
result["bindings"] = "runtime"
result["features"] = "runtime"
# Preserved categories (direct mapping)
result["init"] = "init"
result["audio"] = "audio"
result["optimization"] = "optimization"
result["security"] = "security"
# Global constant for legacy category mapping
const LEGACY_CATEGORY_MAP* = initLegacyCategoryMap()
# #############################################################################
# Legacy Flag Migration Functions
# #############################################################################
proc mapLegacyFlagToDomain*(flagName: string, category: string = ""): string =
## Map a legacy USE flag to its corresponding domain
## If category is provided, use it for mapping
## Otherwise, try to infer from common flag names
# If category is provided and exists in legacy map, use it
if category.len > 0 and LEGACY_CATEGORY_MAP.hasKey(category):
let mappedDomain = LEGACY_CATEGORY_MAP[category]
# Skip special cases that aren't runtime domains
if mappedDomain notin ["profile", "build-mode"]:
return mappedDomain
# Infer domain from common flag names
case flagName
# Init system flags
of "systemd", "dinit", "openrc", "runit", "s6":
return "init"
# Graphics flags
of "X", "wayland", "vulkan", "opengl", "mesa", "gtk", "qt":
return "graphics"
# Audio flags
of "pipewire", "pulseaudio", "alsa", "jack":
return "audio"
# Security flags
of "pie", "relro", "hardened", "fortify", "stack-protector":
return "security"
# Optimization flags
of "lto", "pgo", "march-native", "debug", "strip":
return "optimization"
# Integration flags
of "docker", "podman", "nipcells", "libvirt", "nexus-api", "nexus-security", "nexus-monitor":
return "integration"
# Network flags
of "ipv6", "wireguard", "zerotier", "mesh", "p2p", "ipfs":
return "network"
# Developer flags
of "debugger", "profiler", "lsp", "repl", "hot-reload", "sanitizer":
return "developer"
# Runtime flags (default for unknown)
else:
return "runtime"
proc mapLegacyCategoryToDomain*(category: string): string =
## Map a legacy category name to a domain name
## Returns empty string if category should not be mapped to a domain
if LEGACY_CATEGORY_MAP.hasKey(category):
let mapped = LEGACY_CATEGORY_MAP[category]
# Filter out special cases
if mapped in ["profile", "build-mode"]:
return ""
return mapped
# Unknown category defaults to runtime
return "runtime"
proc isLegacyCategory*(category: string): bool =
## Check if a category name is a legacy category
result = LEGACY_CATEGORY_MAP.hasKey(category)
proc getLegacyCategories*(): seq[string] =
## Get all legacy category names
result = @[]
for category in LEGACY_CATEGORY_MAP.keys:
result.add(category)