wand/wand.go
2025-08-26 03:21:35 +02:00

121 lines
2.2 KiB
Go

package wand
import (
"fmt"
"os"
"path"
)
type Config struct {
file func(Cmd) *file
merge []Config
fromOption bool
optional bool
test string
}
type Cmd struct {
name string
impl any
subcommands []Cmd
isDefault bool
minPositional int
maxPositional int
shortForms []string
description string
isHelp bool
version string
}
// name needs to be valid symbol. The application name should also be a valid symbol,
// though not mandatory. If it is not, the environment variables may not work properly.
func Command(name string, impl any, subcmds ...Cmd) Cmd {
return command(name, impl, subcmds...)
}
func Default(cmd Cmd) Cmd {
cmd.isDefault = true
return cmd
}
func Args(cmd Cmd, min, max int) Cmd {
cmd.minPositional = min
cmd.maxPositional = max
return cmd
}
func ShortFormOptions(cmd Cmd, f ...string) Cmd {
cmd.shortForms = append(cmd.shortForms, f...)
for i := range cmd.subcommands {
cmd.subcommands[i] = ShortFormOptions(
cmd.subcommands[i],
f...,
)
}
return cmd
}
func Version(cmd Cmd, version string) Cmd {
cmd.subcommands = append(
cmd.subcommands,
Cmd{name: "version", version: version},
)
return cmd
}
func MergeConfig(conf ...Config) Config {
return Config{
merge: conf,
}
}
func OptionalConfig(conf Config) Config {
conf.optional = true
for i := range conf.merge {
conf.merge[i] = OptionalConfig(conf.merge[i])
}
return conf
}
func Etc() Config {
return OptionalConfig(Config{
file: func(cmd Cmd) *file {
return fileReader(path.Join("/etc", cmd.name, "config"))
},
})
}
func UserConfig() Config {
return OptionalConfig(MergeConfig(
Config{
file: func(cmd Cmd) *file {
return fileReader(
path.Join(os.Getenv("HOME"), fmt.Sprintf(".%s", cmd.name), "config"),
)
},
},
Config{
file: func(cmd Cmd) *file {
return fileReader(
path.Join(os.Getenv("HOME"), ".config", cmd.name, "config"),
)
},
},
))
}
func ConfigFromOption() Config {
return Config{fromOption: true}
}
func SystemConfig() Config {
return MergeConfig(Etc(), UserConfig(), ConfigFromOption())
}
func Exec(impl any, conf ...Config) {
exec(os.Stdin, os.Stdout, os.Stderr, os.Exit, wrap(impl), MergeConfig(conf...), os.Environ(), os.Args)
}