252 lines
8.8 KiB
Nim
252 lines
8.8 KiB
Nim
## NimPak CLI - Next-generation package manager for NexusOS
|
|
##
|
|
## Main entry point for the `nip` command-line tool.
|
|
## Provides atomic, reproducible package management with ACUL compliance.
|
|
|
|
import std/[os, strformat, strutils, posix, asyncdispatch, tables, sequtils]
|
|
import nimpak/cli/[core, commands, enhanced_search, diagnostics_commands, setup_commands]
|
|
import nimpak/cli/help
|
|
import nimpak/cli/graft_commands as graft # Variant system integration
|
|
import nimpak/cli/build_commands as build # Source building with variants
|
|
import nimpak/cli/variant_switch # Variant switching commands
|
|
import nimpak/cli/bootstrap_commands # Build tool bootstrap
|
|
|
|
# import nip/doctor
|
|
# import nip/cli/resolve_command # Dependency resolution commands
|
|
import nimpak/config
|
|
# import nip/[manifest_parser, archives, nip_installer, namespace, cas, types]
|
|
|
|
const
|
|
NimPakVersion = "0.1.0"
|
|
NimPakBanner = """
|
|
🌱 NimPak v$1 - Universal Package Manager for NexusOS
|
|
Atomic • Reproducible • ACUL Compliant • 205,000+ Packages
|
|
""" % [NimPakVersion]
|
|
|
|
proc showConfigCommand(): CommandResult =
|
|
## Show current configuration
|
|
let config = loadConfig()
|
|
let output = fmt"""
|
|
Current Configuration:
|
|
Programs Dir: {config.programsDir}
|
|
Links Dir: {config.linksDir}
|
|
Cache Dir: {config.cacheDir}
|
|
Active Profile: {config.activeProfile}
|
|
Adapters: {config.adapters.len} enabled
|
|
Variant Targets: {config.defaultTarget}
|
|
"""
|
|
return successResult(output)
|
|
|
|
proc initConfigCommand(): CommandResult =
|
|
## Initialize default configuration
|
|
try:
|
|
initDefaultConfig()
|
|
return successResult(fmt"Initialized default configuration at {getConfigPath()}")
|
|
except Exception as e:
|
|
return errorResult(fmt"Failed to initialize configuration: {e.msg}")
|
|
proc dispatchCommand(args: seq[string]): int =
|
|
## Main command dispatcher with advanced CLI features
|
|
if args.len == 0:
|
|
showMainHelp()
|
|
return 0
|
|
|
|
# Parse global options
|
|
let (globalOptions, remainingArgs) = parseGlobalOptions(args)
|
|
discard initCliContext(globalOptions)
|
|
|
|
if remainingArgs.len == 0:
|
|
showMainHelp()
|
|
return 0
|
|
|
|
let command = remainingArgs[0].toLower()
|
|
let commandArgs = remainingArgs[1..^1]
|
|
|
|
# Check PATH configuration (except for setup command itself)
|
|
if command != "setup" and not checkPathConfigured():
|
|
echo "⚠️ NIP binary path is NOT in your PATH."
|
|
echo " Run `nip setup user` to automatically configure your shell."
|
|
echo ""
|
|
|
|
var commandRes: CommandResult
|
|
|
|
try:
|
|
case command:
|
|
# Core package management commands
|
|
of "install":
|
|
if commandArgs.len == 0:
|
|
commandRes = errorResult("Usage: nip install <package> [options]")
|
|
else:
|
|
let target = commandArgs[0]
|
|
if target.endsWith(".nip"):
|
|
commandRes = errorResult("Local NIP installation not yet migrated")
|
|
else:
|
|
let verbose = globalOptions.verbose
|
|
# Map 'install' to 'graft' for now as per MVP
|
|
let exitCode = graft.graftCommand(target, verbose)
|
|
commandRes = if exitCode == 0: successResult("Package installed") else: errorResult("Install failed")
|
|
|
|
of "remove":
|
|
if commandArgs.len == 0:
|
|
commandRes = errorResult("Usage: nip remove <package>")
|
|
else:
|
|
let verbose = globalOptions.verbose
|
|
let exitCode = graft.removeCommand(commandArgs[0], verbose)
|
|
commandRes = if exitCode == 0: successResult("Package removed") else: errorResult("Failed to remove package")
|
|
|
|
of "update":
|
|
commandRes = errorResult("Update command not yet implemented")
|
|
|
|
of "setup":
|
|
commandRes = setup_commands.setupCommand(commandArgs)
|
|
|
|
of "search":
|
|
if commandArgs.len == 0:
|
|
commandRes = errorResult("Usage: nip search <query>")
|
|
else:
|
|
# Check for --remote flag manually if needed, or pass all args
|
|
let queryArgs = commandArgs.filterIt(it != "--remote")
|
|
let query = queryArgs.join(" ")
|
|
commandRes = enhanced_search.enhancedSearchCommand(query)
|
|
|
|
# Variant & Graft commands
|
|
of "graft":
|
|
if commandArgs.len == 0:
|
|
commandRes = errorResult("Usage: nip graft <package>")
|
|
else:
|
|
let verbose = globalOptions.verbose
|
|
let exitCode = graft.graftCommand(commandArgs[0], verbose)
|
|
commandRes = if exitCode == 0: successResult("Graft complete") else: errorResult("Graft failed")
|
|
|
|
of "switch":
|
|
if commandArgs.len < 2:
|
|
commandRes = errorResult("Usage: nip switch <package> <variant>")
|
|
else:
|
|
let exitCode = variant_switch.switchCommand(commandArgs[0], commandArgs[1])
|
|
commandRes = if exitCode == 0: successResult("Switch complete") else: errorResult("Switch failed")
|
|
|
|
of "build":
|
|
if commandArgs.len == 0:
|
|
commandRes = errorResult("Usage: nip build <package> [flags]")
|
|
else:
|
|
let pkg = commandArgs[0]
|
|
let flags = if commandArgs.len > 1: commandArgs[1..^1] else: @[]
|
|
let verbose = globalOptions.verbose
|
|
let exitCode = build.buildCommand(pkg, flags, "auto", verbose)
|
|
commandRes = if exitCode == 0: successResult("Build complete") else: errorResult("Build failed")
|
|
|
|
of "bootstrap":
|
|
if commandArgs.len == 0:
|
|
commandRes = errorResult("Usage: nip bootstrap <list|install|remove|info> ...")
|
|
else:
|
|
let subCmd = commandArgs[0].toLower()
|
|
let exitCode = case subCmd
|
|
of "list": bootstrap_commands.bootstrapListRecipesCommand()
|
|
of "install":
|
|
if commandArgs.len > 1: bootstrap_commands.bootstrapInstallCommand(commandArgs[1]) else: 1
|
|
of "remove":
|
|
if commandArgs.len > 1: bootstrap_commands.bootstrapRemoveCommand(commandArgs[1]) else: 1
|
|
of "info":
|
|
if commandArgs.len > 1: bootstrap_commands.bootstrapInfoCommand(commandArgs[1]) else: 1
|
|
of "recipes": bootstrap_commands.bootstrapListRecipesCommand()
|
|
of "update-recipes": bootstrap_commands.bootstrapUpdateRecipesCommand()
|
|
of "help":
|
|
bootstrap_commands.bootstrapHelpCommand()
|
|
0
|
|
else: 1
|
|
|
|
commandRes = if exitCode == 0: successResult("Bootstrap command successful") else: errorResult("Bootstrap command failed")
|
|
|
|
# Cell Management
|
|
of "cell":
|
|
commandRes = errorResult("Cell commands not fully implemented in this dispatch")
|
|
|
|
# App / Nexter / GC / CAS stubs
|
|
of "app", "nexter", "gc", "cas":
|
|
commandRes = successResult(fmt"Command '{command}' is a placeholder in this MVP")
|
|
|
|
# Reproducibility commands
|
|
of "lock":
|
|
commandRes = lockCommand()
|
|
|
|
of "restore":
|
|
if commandArgs.len == 0:
|
|
commandRes = errorResult("Usage: nip restore <lockfile>")
|
|
else:
|
|
commandRes = restoreCommand(commandArgs[0])
|
|
|
|
of "diff":
|
|
commandRes = diffCommand()
|
|
|
|
# Verification commands
|
|
of "verify":
|
|
commandRes = enhanced_search.verifyCommand(commandArgs)
|
|
|
|
of "diagnose":
|
|
if commandArgs.len == 0:
|
|
commandRes = errorResult("Usage: nip diagnose <cid>")
|
|
else:
|
|
commandRes = enhanced_search.diagnoseCommand(commandArgs)
|
|
|
|
# Doctor/health check commands
|
|
of "doctor":
|
|
let autoRepair = "--fix" in commandArgs or "--auto" in commandArgs
|
|
let outputFormat = if "--json" in commandArgs: "json" else: "plain"
|
|
let report = waitFor diagnostics_commands.nipDoctor(outputFormat, autoRepair)
|
|
echo report
|
|
commandRes = successResult("System health check completed")
|
|
|
|
# Configuration commands
|
|
of "config":
|
|
if commandArgs.len == 0:
|
|
commandRes = errorResult("Usage: nip config <show|init|path>")
|
|
else:
|
|
case commandArgs[0].toLower():
|
|
of "show": commandRes = showConfigCommand()
|
|
of "init": commandRes = initConfigCommand()
|
|
of "path": commandRes = successResult(getConfigPath())
|
|
else: commandRes = errorResult("Unknown config command")
|
|
|
|
of "resolve":
|
|
commandRes = errorResult("Resolve command not yet migrated")
|
|
|
|
of "explain":
|
|
commandRes = errorResult("Explain command not yet migrated")
|
|
|
|
# Help commands
|
|
of "help", "--help", "-h":
|
|
if commandArgs.len > 0:
|
|
showCommandHelp(commandArgs[0])
|
|
else:
|
|
showMainHelp()
|
|
return 0
|
|
|
|
of "version", "--version", "-v":
|
|
echo NimPakBanner
|
|
return 0
|
|
|
|
else:
|
|
commandRes = errorResult(fmt"Unknown command: {command}")
|
|
|
|
except Exception as e:
|
|
commandRes = errorResult(fmt"Unexpected error: {e.msg}")
|
|
|
|
# Output result
|
|
if not commandRes.success:
|
|
echo fmt"❌ Error: {commandRes.message}"
|
|
return 1
|
|
else:
|
|
if commandRes.message != "":
|
|
echo commandRes.message
|
|
return 0
|
|
|
|
|
|
|
|
# =============================================================================
|
|
# Main Entry Point
|
|
# =============================================================================
|
|
|
|
when isMainModule:
|
|
let args = commandLineParams()
|
|
let exitCode = dispatchCommand(args)
|
|
quit(exitCode)
|