mirror of
https://github.com/luxfi/cli.git
synced 2026-10-30 17:01:20 +00:00
Renames LUX_-prefixed env vars to canonical, non-noisy forms: - LUX_MNEMONIC -> MNEMONIC (deploy script + LLM doc) - LUX_PRIVATE_KEY -> PRIVATE_KEY (deploy script + LLM doc) - LUX_INSECURE_TLS -> INSECURE_TLS - LUX_NODE_ENDPOINT -> NODE_ENDPOINT - LUX_NETWORK_TYPE -> NETWORK_TYPE (backend gRPC server selector) - LUX_RPC_URL -> RPC_URL - LUX_NODE_ROOT -> NODE_ROOT - LUX_CHART_PATH -> CHART_PATH - LUX_CHAINS_FILE -> CHAINS_FILE - LUX_KMS_ROOT_KEY -> KMS_ROOT_KEY - LUX_WC_PROJECT_ID -> WC_PROJECT_ID (WalletConnect) - LUX_BLS_KEY -> BLS_KEY (was already supported via getEnv()) - LUX_KEY_INDEX -> KEY_INDEX (was already supported via getEnv()) pkg/key/backend_env.go: removed the LUX_-prefix-stripping getEnv() helper (now reads env vars by exact name) and dropped the broken "MNEMONIC / MNEMONIC" / "PRIVATE_KEY / PRIVATE_KEY" doc comments which were a previous incomplete rename. NOT renamed (defined in upstream luxfi/constants — separate concern): - LUX_NODE_PATH (constants.EnvNodePath) - LUX_NETRUNNER_PATH (constants.EnvNetrunnerPath) - LUX_EVM_PATH (constants.EnvEVMPath) - LUX_PLUGINS_DIR (constants.EnvPluginsDir) Doc comments referencing those env vars (cmd/root.go, cmd/networkcmd/start.go, cmd/nodecmd/link.go) describe the constants-defined names accurately and are left alone. NOT renamed (script-local variables, not env vars): - LUX_ZONE in scripts/update-cloudflare-dns.sh (Cloudflare DNS zone ID) - LUX_BIN_DIR in scripts/install.sh (~/.lux/bin path constant) BREAKING: external callers/operators must update env var names. Per CLAUDE.md no-backwards-compatibility rule, the old forms are removed.
162 lines
4.3 KiB
Go
162 lines
4.3 KiB
Go
// Copyright (C) 2022-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package prompts
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// MissingOpt describes a required option that was not provided.
|
|
type MissingOpt struct {
|
|
Flag string // e.g., "--chain-id"
|
|
Env string // e.g., "CHAIN_ID" (optional)
|
|
Prompt string // e.g., "EVM chain ID" - used for interactive prompts
|
|
Note string // optional additional context
|
|
Default string // optional default value hint
|
|
}
|
|
|
|
// MissingError creates a clear, actionable error listing all missing options.
|
|
// The error message follows UNIX conventions and guides users to the right flags.
|
|
func MissingError(cmd string, missing []MissingOpt) error {
|
|
if len(missing) == 0 {
|
|
return nil
|
|
}
|
|
|
|
var b strings.Builder
|
|
b.WriteString("missing required options:\n")
|
|
for _, m := range missing {
|
|
if m.Env != "" {
|
|
fmt.Fprintf(&b, " %s (or %s)", m.Flag, m.Env)
|
|
} else {
|
|
fmt.Fprintf(&b, " %s", m.Flag)
|
|
}
|
|
if m.Note != "" {
|
|
fmt.Fprintf(&b, " - %s", m.Note)
|
|
}
|
|
b.WriteString("\n")
|
|
}
|
|
fmt.Fprintf(&b, "\nrun '%s --help' to see all options", cmd)
|
|
if IsInteractive() {
|
|
b.WriteString("\nor run on a TTY to be prompted interactively")
|
|
}
|
|
return errors.New(b.String())
|
|
}
|
|
|
|
// PromptOrFail handles the common pattern of prompting for missing values.
|
|
// In interactive mode, prompts for each missing option.
|
|
// In non-interactive mode, returns an error listing all missing options.
|
|
//
|
|
// Usage:
|
|
//
|
|
// missing := []prompts.MissingOpt{}
|
|
// if chainID == "" {
|
|
// missing = append(missing, prompts.MissingOpt{Flag: "--chain-id", Env: "CHAIN_ID", Prompt: "EVM chain ID"})
|
|
// }
|
|
// if err := prompts.PromptOrFail("lux chain create", missing, func(m MissingOpt) (string, error) {
|
|
// return app.Prompt.CaptureString(m.Prompt)
|
|
// }, &chainID); err != nil {
|
|
// return err
|
|
// }
|
|
func PromptOrFail(cmd string, missing []MissingOpt, promptFn func(MissingOpt) (string, error), targets ...*string) error {
|
|
if len(missing) == 0 {
|
|
return nil
|
|
}
|
|
|
|
if len(missing) != len(targets) {
|
|
return fmt.Errorf("internal error: %d missing options but %d targets", len(missing), len(targets))
|
|
}
|
|
|
|
// Non-interactive: fail with complete error message
|
|
if !IsInteractive() {
|
|
return MissingError(cmd, missing)
|
|
}
|
|
|
|
// Interactive: prompt for each missing value
|
|
for i, m := range missing {
|
|
val, err := promptFn(m)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get %s: %w", m.Flag, err)
|
|
}
|
|
*targets[i] = val
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Validator holds options being collected and tracks missing ones.
|
|
// Use this for clean, declarative option handling.
|
|
type Validator struct {
|
|
cmd string
|
|
missing []MissingOpt
|
|
values []*string
|
|
}
|
|
|
|
// NewValidator creates a validator for a command.
|
|
func NewValidator(cmd string) *Validator {
|
|
return &Validator{cmd: cmd}
|
|
}
|
|
|
|
// Require marks a value as required. If empty, adds to missing list.
|
|
func (v *Validator) Require(target *string, opt MissingOpt) *Validator {
|
|
if *target == "" {
|
|
v.missing = append(v.missing, opt)
|
|
v.values = append(v.values, target)
|
|
}
|
|
return v
|
|
}
|
|
|
|
// RequireWithDefault marks a value as required with a default.
|
|
// Uses the default if empty and non-interactive, otherwise prompts.
|
|
func (v *Validator) RequireWithDefault(target *string, opt MissingOpt, defaultVal string) *Validator {
|
|
if *target == "" {
|
|
if !IsInteractive() {
|
|
*target = defaultVal
|
|
} else {
|
|
opt.Default = defaultVal
|
|
v.missing = append(v.missing, opt)
|
|
v.values = append(v.values, target)
|
|
}
|
|
}
|
|
return v
|
|
}
|
|
|
|
// Optional sets a default if the value is empty (no prompting).
|
|
func (v *Validator) Optional(target *string, defaultVal string) *Validator {
|
|
if *target == "" {
|
|
*target = defaultVal
|
|
}
|
|
return v
|
|
}
|
|
|
|
// Missing returns the list of missing options.
|
|
func (v *Validator) Missing() []MissingOpt {
|
|
return v.missing
|
|
}
|
|
|
|
// HasMissing returns true if any required options are missing.
|
|
func (v *Validator) HasMissing() bool {
|
|
return len(v.missing) > 0
|
|
}
|
|
|
|
// Resolve prompts for missing values (interactive) or returns error (non-interactive).
|
|
func (v *Validator) Resolve(promptFn func(MissingOpt) (string, error)) error {
|
|
if !v.HasMissing() {
|
|
return nil
|
|
}
|
|
|
|
if !IsInteractive() {
|
|
return MissingError(v.cmd, v.missing)
|
|
}
|
|
|
|
for i, m := range v.missing {
|
|
val, err := promptFn(m)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get %s: %w", m.Flag, err)
|
|
}
|
|
*v.values[i] = val
|
|
}
|
|
return nil
|
|
}
|