2025-08-18 14:24:31 +02:00
|
|
|
package wand
|
|
|
|
|
|
2025-08-24 01:45:25 +02:00
|
|
|
import (
|
2025-08-24 04:46:54 +02:00
|
|
|
"fmt"
|
2025-08-24 01:45:25 +02:00
|
|
|
"os"
|
|
|
|
|
"path"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Config struct {
|
2025-08-24 04:46:54 +02:00
|
|
|
file func(Cmd) *file
|
2025-08-24 01:45:25 +02:00
|
|
|
merge []Config
|
|
|
|
|
fromOption bool
|
|
|
|
|
optional bool
|
2025-08-26 03:21:35 +02:00
|
|
|
test string
|
2025-08-24 01:45:25 +02:00
|
|
|
}
|
2025-08-18 14:24:31 +02:00
|
|
|
|
|
|
|
|
type Cmd struct {
|
|
|
|
|
name string
|
|
|
|
|
impl any
|
|
|
|
|
subcommands []Cmd
|
|
|
|
|
isDefault bool
|
|
|
|
|
minPositional int
|
|
|
|
|
maxPositional int
|
|
|
|
|
shortForms []string
|
|
|
|
|
description string
|
|
|
|
|
isHelp bool
|
2025-08-26 03:21:35 +02:00
|
|
|
version string
|
2025-08-18 14:24:31 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-26 03:21:35 +02:00
|
|
|
// 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.
|
2025-08-18 14:24:31 +02:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-24 01:45:25 +02:00
|
|
|
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...,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 14:24:31 +02:00
|
|
|
return cmd
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-26 03:21:35 +02:00
|
|
|
func Version(cmd Cmd, version string) Cmd {
|
|
|
|
|
cmd.subcommands = append(
|
|
|
|
|
cmd.subcommands,
|
|
|
|
|
Cmd{name: "version", version: version},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return cmd
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-24 01:45:25 +02:00
|
|
|
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{
|
2025-08-24 04:46:54 +02:00
|
|
|
file: func(cmd Cmd) *file {
|
2025-08-24 01:45:25 +02:00
|
|
|
return fileReader(path.Join("/etc", cmd.name, "config"))
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func UserConfig() Config {
|
2025-08-24 04:46:54 +02:00
|
|
|
return OptionalConfig(MergeConfig(
|
|
|
|
|
Config{
|
|
|
|
|
file: func(cmd Cmd) *file {
|
|
|
|
|
return fileReader(
|
|
|
|
|
path.Join(os.Getenv("HOME"), fmt.Sprintf(".%s", cmd.name), "config"),
|
|
|
|
|
)
|
|
|
|
|
},
|
2025-08-24 01:45:25 +02:00
|
|
|
},
|
2025-08-24 04:46:54 +02:00
|
|
|
Config{
|
|
|
|
|
file: func(cmd Cmd) *file {
|
|
|
|
|
return fileReader(
|
|
|
|
|
path.Join(os.Getenv("HOME"), ".config", cmd.name, "config"),
|
|
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
))
|
2025-08-24 01:45:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
2025-08-18 14:24:31 +02:00
|
|
|
}
|