wand/input.go

185 lines
3.4 KiB
Go
Raw Permalink Normal View History

2025-08-18 14:24:31 +02:00
package wand
import (
2025-09-01 04:10:35 +02:00
"code.squareroundforest.org/arpio/bind"
2025-08-18 14:24:31 +02:00
"fmt"
"reflect"
)
2025-08-24 01:45:25 +02:00
func validateKeyValues(cmd Cmd, keyValues map[string][]string, originalNames map[string]string) error {
2025-08-18 14:24:31 +02:00
mf := mapFields(cmd.impl)
2025-08-24 01:45:25 +02:00
for name, values := range keyValues {
2025-08-18 14:24:31 +02:00
f, ok := mf[name]
if !ok {
continue
}
for _, fi := range f {
2025-09-01 02:07:48 +02:00
if len(values) > 1 && !fi.List() {
2025-08-18 14:24:31 +02:00
return fmt.Errorf(
2025-09-01 02:07:48 +02:00
"expected only one value, received %d, for %s",
2025-08-18 14:24:31 +02:00
len(values),
2025-08-24 01:45:25 +02:00
originalNames[name],
2025-08-18 14:24:31 +02:00
)
}
for _, v := range values {
2025-09-01 02:07:48 +02:00
if !canScan(fi.Type(), v) {
return fmt.Errorf("type mismatch: %s", originalNames[name])
2025-08-18 14:24:31 +02:00
}
}
}
}
return nil
}
2025-08-24 01:45:25 +02:00
func validateConfig(cmd Cmd, c config) error {
2025-09-01 02:07:48 +02:00
if err := validateKeyValues(cmd, c.values, c.originalNames); err != nil {
return fmt.Errorf("config: %w", err)
}
return nil
2025-08-24 01:45:25 +02:00
}
func validateEnv(cmd Cmd, e env) error {
2025-09-01 02:07:48 +02:00
if err := validateKeyValues(cmd, e.values, e.originalNames); err != nil {
return fmt.Errorf("environment: %w", err)
}
return nil
2025-08-24 01:45:25 +02:00
}
func validateOptions(cmd Cmd, o []option, conf Config) error {
2025-09-05 03:19:00 +02:00
var names []string
2025-12-10 20:31:10 +01:00
ms := shortFormsToLong(cmd.shortForms)
ml := longFormsToShort(cmd.shortForms)
2025-08-18 14:24:31 +02:00
mo := make(map[string][]option)
for _, oi := range o {
n := oi.name
2025-09-05 03:19:00 +02:00
if oi.shortForm {
ln, ok := ms[n]
if !ok {
return fmt.Errorf("option not supported: -%s", n)
}
2025-08-18 14:24:31 +02:00
n = ln
}
2025-09-05 03:19:00 +02:00
names = append(names, n)
2025-08-18 14:24:31 +02:00
mo[n] = append(mo[n], oi)
}
2025-09-01 02:07:48 +02:00
hasConfigOption := hasConfigFromOption(conf)
2025-08-18 14:24:31 +02:00
mf := mapFields(cmd.impl)
2025-09-05 03:19:00 +02:00
for _, n := range names {
os := mo[n]
2025-08-24 01:45:25 +02:00
en := "--" + n
2025-12-10 20:31:10 +01:00
for _, sn := range ml[n] {
2025-08-24 01:45:25 +02:00
en += ", -" + sn
}
2025-09-01 02:07:48 +02:00
if hasConfigOption && n == "config" {
continue
}
2025-08-18 14:24:31 +02:00
f := mf[n]
2025-08-24 01:45:25 +02:00
if len(f) == 0 {
return fmt.Errorf("option not supported: %s", en)
}
2025-08-18 14:24:31 +02:00
2025-08-24 01:45:25 +02:00
for _, fi := range f {
2025-09-01 02:07:48 +02:00
if len(os) > 1 && !fi.List() {
2025-08-18 14:24:31 +02:00
return fmt.Errorf(
"expected only one value, received %d, as option, %s",
len(os),
en,
)
}
for _, oi := range os {
2025-09-01 02:07:48 +02:00
if oi.value.isBool && fi.Type() != bind.Bool {
2025-08-18 14:24:31 +02:00
return fmt.Errorf(
"received boolean value for field that does not accept it: %s",
en,
)
}
2025-09-01 02:07:48 +02:00
if !oi.value.isBool && !canScan(fi.Type(), oi.value.str) {
2025-08-18 14:24:31 +02:00
return fmt.Errorf(
"option cannot be applied, type mismatch: %s",
en,
)
}
}
}
}
return nil
}
func validatePositionalArgs(cmd Cmd, a []string) error {
2025-09-01 02:07:48 +02:00
p, variadic := positional(cmd.impl)
min := len(p)
max := len(p)
if variadic {
2025-08-18 14:24:31 +02:00
min--
max = -1
}
if cmd.minPositional > min {
min = cmd.minPositional
}
if cmd.maxPositional > 0 {
max = cmd.maxPositional
}
if len(a) < min {
return fmt.Errorf("not enough positional arguments, expected minimum %d", min)
}
if max >= 0 && len(a) > max {
return fmt.Errorf("too many positional arguments, expected maximum %d", max)
}
for i, ai := range a {
var pi reflect.Type
2025-09-01 02:07:48 +02:00
if i >= len(p) {
pi = p[len(p)-1]
2025-08-18 14:24:31 +02:00
} else {
pi = p[i]
}
2025-09-01 02:07:48 +02:00
if !canScanType(pi, ai) {
2025-08-18 14:24:31 +02:00
return fmt.Errorf(
2025-09-01 02:07:48 +02:00
"cannot apply positional argument at index %d, expecting %s",
2025-08-18 14:24:31 +02:00
i,
2025-09-01 02:07:48 +02:00
fmt.Sprint(pi.Kind()),
2025-08-18 14:24:31 +02:00
)
}
}
return nil
}
2025-08-24 01:45:25 +02:00
func validateInput(cmd Cmd, conf Config, c config, e env, cl commandLine) error {
if err := validateConfig(cmd, c); err != nil {
return err
}
2025-08-18 14:24:31 +02:00
if err := validateEnv(cmd, e); err != nil {
return err
}
2025-08-24 01:45:25 +02:00
if err := validateOptions(cmd, cl.options, conf); err != nil {
2025-08-18 14:24:31 +02:00
return err
}
if err := validatePositionalArgs(cmd, cl.positional); err != nil {
return err
}
return nil
}