Documentation
¶
Index ¶
- Constants
- Variables
- func IsSupportedKind(k reflect.Kind) bool
- func NewConfigWithMerge[T any](sc *StructConfig[T], merger *Merger[T], fs *pflag.FlagSet, opt ...Option) (*T, error)
- type AnyCallbackFunc
- type AnyEqualFunc
- type AnyReceptor
- type BoolReceptor
- type Builder
- type Config
- type ConfigBuilder
- type ConfigItem
- type EnvVar
- type FloatReceptor
- type IntReceptor
- type Merger
- type Option
- type Receptor
- type StringReceptor
- type StructConfig
- type StructField
- type Supported
- type Tag
- type Type
- type UintReceptor
- type Unsigned
Examples ¶
Constants ¶
const ( TagName = internal.TagName TagUsage = internal.TagUsage TagDefault = internal.TagDefault TagShort = internal.TagShort )
Variables ¶
var ( ErrStructConfig = internal.ErrStructConfig ErrNotStruct = internal.ErrNotStruct ErrNotStructPointer = internal.ErrNotStructPointer )
Functions ¶
func IsSupportedKind ¶
func NewConfigWithMerge ¶ added in v0.4.0
func NewConfigWithMerge[T any]( sc *StructConfig[T], merger *Merger[T], fs *pflag.FlagSet, opt ...Option, ) (*T, error)
NewConfigWithMerge generates a Config by taking into account default values, environment variables, and command-line arguments.
It overrides the default values with values obtained from environment variables and further overrides them with the values from command-line arguments. The command-line arguments are obtained by calling StructConfig.SetFlags on the fs and then parsing with pflag.FlagSet.Parse.
In this process, the values to be parsed are those specified with WithArguments. If none are specified, it uses os.Args.
Example ¶
package main
import (
"fmt"
"os"
"github.com/berquerant/structconfig"
"github.com/spf13/pflag"
)
func main() {
type T struct {
Default string `name:"default_value" default:"default"`
Env string `name:"env_value" default:"env_default"`
Flag string `name:"flag_value" default:"flag_default"`
Override string `name:"override_value" default:"override_default"`
}
envs := map[string]string{
"ENV_VALUE": "from_env",
"OVERRIDE_VALUE": "should_not_appear",
}
args := []string{
"--flag_value", "from_flag",
"--override_value", "overrided",
}
for k, v := range envs {
os.Setenv(k, v)
}
defer func() {
for k := range envs {
os.Unsetenv(k)
}
}()
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
c, err := structconfig.NewConfigWithMerge[T](
structconfig.New[T](),
structconfig.NewMerger[T](),
fs,
structconfig.WithArguments(args),
)
if err != nil {
panic(err)
}
fmt.Println(c.Default, c.Env, c.Flag, c.Override)
}
Output: default from_env from_flag overrided
Types ¶
type AnyCallbackFunc ¶
type AnyCallbackFunc = func(StructField, string, func() reflect.Value) error
type AnyEqualFunc ¶
type AnyReceptor ¶
type AnyReceptor = internal.AnyReceptor
type BoolReceptor ¶
type BoolReceptor = internal.BoolReceptor
type Builder ¶ added in v0.5.0
type Builder[T any] struct { // contains filtered or unexported fields }
Example ¶
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/berquerant/structconfig"
"github.com/spf13/pflag"
)
func main() {
type T struct {
Default string `json:"default" name:"default_value" default:"default"`
Env string `json:"env" name:"env_value" default:"env_default"`
Flag string `json:"flag" name:"flag_value" default:"flag_default"`
File string `json:"file" name:"file_value" default:"file_default"`
Override string `json:"override" name:"override_value" default:"override_default"`
}
file := []byte(`{"file":"from_file","override":"from_file"}`)
envs := map[string]string{
"ENV_VALUE": "from_env",
"OVERRIDE_VALUE": "should_not_appear",
}
args := []string{
"--flag_value", "from_flag",
"--override_value", "overrided",
}
for k, v := range envs {
os.Setenv(k, v)
}
defer func() {
for k := range envs {
os.Unsetenv(k)
}
}()
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
c, err := structconfig.NewBuilder[T](structconfig.New[T](), structconfig.NewMerger[T]()).
Add(func(sc *structconfig.StructConfig[T]) (*T, error) {
var t T
if err := sc.FromDefault(&t); err != nil {
return nil, err
}
if err := json.Unmarshal(file, &t); err != nil {
return nil, err
}
return &t, nil
}).
Add(func(sc *structconfig.StructConfig[T]) (*T, error) {
var t T
if err := sc.FromEnv(&t); err != nil {
return nil, err
}
return &t, nil
}).
Add(func(sc *structconfig.StructConfig[T]) (*T, error) {
if err := sc.SetFlags(fs); err != nil {
return nil, err
}
if err := fs.Parse(args); err != nil {
return nil, err
}
var t T
if err := sc.FromFlags(&t, fs); err != nil {
return nil, err
}
return &t, nil
}).
Build()
if err != nil {
panic(err)
}
fmt.Println(c.Default, c.Env, c.Flag, c.File, c.Override)
}
Output: default from_env from_flag from_file overrided
func NewBuilder ¶ added in v0.5.0
func NewBuilder[T any](sc *StructConfig[T], merger *Merger[T]) *Builder[T]
type Config ¶
type Config struct {
AnyCallback *ConfigItem[AnyCallbackFunc]
AnyEqual *ConfigItem[AnyEqualFunc]
Prefix *ConfigItem[string]
Arguments *ConfigItem[[]string]
}
type ConfigBuilder ¶
type ConfigBuilder struct {
// contains filtered or unexported fields
}
func NewConfigBuilder ¶
func NewConfigBuilder() *ConfigBuilder
func (*ConfigBuilder) AnyCallback ¶
func (s *ConfigBuilder) AnyCallback(v AnyCallbackFunc) *ConfigBuilder
func (*ConfigBuilder) AnyEqual ¶
func (s *ConfigBuilder) AnyEqual(v AnyEqualFunc) *ConfigBuilder
func (*ConfigBuilder) Arguments ¶ added in v0.4.0
func (s *ConfigBuilder) Arguments(v []string) *ConfigBuilder
func (*ConfigBuilder) Build ¶
func (s *ConfigBuilder) Build() *Config
func (*ConfigBuilder) Prefix ¶
func (s *ConfigBuilder) Prefix(v string) *ConfigBuilder
type ConfigItem ¶
type ConfigItem[T any] struct { // contains filtered or unexported fields }
func NewConfigItem ¶
func NewConfigItem[T any](defaultValue T) *ConfigItem[T]
func (*ConfigItem[T]) Default ¶
func (s *ConfigItem[T]) Default() T
func (*ConfigItem[T]) Get ¶
func (s *ConfigItem[T]) Get() T
func (*ConfigItem[T]) IsModified ¶
func (s *ConfigItem[T]) IsModified() bool
func (*ConfigItem[T]) Set ¶
func (s *ConfigItem[T]) Set(value T)
type FloatReceptor ¶
type FloatReceptor = internal.FloatReceptor
type IntReceptor ¶
type IntReceptor = internal.IntReceptor
type Merger ¶
Example ¶
package main
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"github.com/berquerant/structconfig"
)
func main() {
type T struct {
I int `name:"i" default:"1"`
S string `name:"s" default:"s"`
II []int `name:"ii" default:"[1]"`
IgnoreWithoutName int
}
callback := func(s structconfig.StructField, v string, fv func() reflect.Value) error {
if s.Name() != "II" {
return errors.New("unexpected field name")
}
var xs []int
if err := json.Unmarshal([]byte(v), &xs); err != nil {
return err
}
fv().Set(reflect.ValueOf(xs))
return nil
}
eq := func(a, b any) (bool, error) {
// expect only []int because int and string are supported by structconfig
xs, ok := a.([]int)
if !ok {
return false, nil
}
ys, ok := b.([]int)
if !ok {
return false, nil
}
if len(xs) != len(ys) {
return false, nil
}
for i, x := range xs {
if x != ys[i] {
return false, nil
}
}
return true, nil
}
m := structconfig.NewMerger[T](
structconfig.WithAnyCallback(callback),
structconfig.WithAnyEqual(eq),
)
got, err := m.Merge(
T{
I: 100,
S: "s", // default
II: []int{100},
},
T{
I: 1, // default
S: "win",
II: []int{1}, // default
},
)
if err != nil {
panic(err)
}
fmt.Println(got.I, got.S, got.II)
}
Output: 100 win [100]
func NewMerger ¶
NewMerger returns a new Merger.
AnyCallback parses "default" tag value and set it. AnyEqual reports true if left equals right when kind of arguments are not supported. Prefix adds a prefix to "default" tag name.
type Option ¶
type Option func(*Config)
func WithAnyCallback ¶
func WithAnyCallback(v AnyCallbackFunc) Option
func WithAnyEqual ¶
func WithAnyEqual(v AnyEqualFunc) Option
func WithArguments ¶ added in v0.4.0
func WithPrefix ¶
type StringReceptor ¶
type StringReceptor = internal.StringReceptor
type StructConfig ¶
type StructConfig[T any] struct { // contains filtered or unexported fields }
func New ¶
func New[T any](opt ...Option) *StructConfig[T]
New returns a new StructConfig.
AnyCallback parses "default" tag value and set it. Prefix adds a prefix to "name", "short", "default" and "usage" tag name.
func (StructConfig[T]) FromDefault ¶
func (sc StructConfig[T]) FromDefault(v *T) error
FromDefault sets "default" tag values to v.
Example ¶
package main
import (
"fmt"
"github.com/berquerant/structconfig"
)
func main() {
type T struct {
B bool `default:"false"`
I int
F float32 `default:"1.1"`
S string `default:"str"`
}
sc := structconfig.New[T]()
var got T
if err := sc.FromDefault(&got); err != nil {
panic(err)
}
fmt.Println(got.B, got.I, got.F, got.S)
}
Output: false 0 1.1 str
func (StructConfig[T]) FromEnv ¶
func (sc StructConfig[T]) FromEnv(v *T) error
FromEnv sets environment variable values to v.
Environment variable name will be
NewEnvVar("name tag value").String()
All '.' and '-' will be replaced with '_', making it all uppsercase.
Example ¶
package main
import (
"fmt"
"os"
"github.com/berquerant/structconfig"
)
func main() {
type T struct {
B bool `name:"bool_value"`
S string `name:"string_value"`
N int `name:"int_value" default:"10"`
N2 int
N3 int `name:"-"`
}
envs := map[string]string{
"BOOL_VALUE": "true",
"STRING_VALUE": "str",
}
for k, v := range envs {
os.Setenv(k, v)
}
defer func() {
for k := range envs {
os.Unsetenv(k)
}
}()
sc := structconfig.New[T]()
var got T
if err := sc.FromEnv(&got); err != nil {
panic(err)
}
fmt.Println(got.B, got.S, got.N, got.N2, got.N3)
}
Output: true str 10 0 0
func (StructConfig[T]) FromFlags ¶
func (sc StructConfig[T]) FromFlags(v *T, fs *pflag.FlagSet) error
FromFlags sets values to v from command-line flags.
Flag name is from "name" tag value.
Example ¶
package main
import (
"errors"
"fmt"
"reflect"
"sort"
"strings"
"github.com/berquerant/structconfig"
"github.com/spf13/pflag"
)
func main() {
type T struct {
B bool `name:"bool_value" usage:"BOOL"`
S string `name:"string_value" default:"str"`
X bool `name:"bool_short" short:"x"`
Ignore1 int
Ignore2 int `name:"-"`
V struct {
S string
} `name:"struct_value"`
Ignore3 struct {
S string
}
}
anyCallback := func(s structconfig.StructField, v string, fv func() reflect.Value) error {
name, ok := s.Tag().Name()
if !ok {
// ignore fields without name
return nil
}
switch name {
case "struct_value":
fv().Set(reflect.ValueOf(struct {
S string
}{
S: v,
}))
return nil
default:
return errors.New("unexpected tag name")
}
}
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
sc := structconfig.New[T](structconfig.WithAnyCallback(anyCallback))
if err := sc.SetFlags(fs); err != nil {
panic(err)
}
flagNames := []string{}
fs.VisitAll(func(f *pflag.Flag) {
flagNames = append(flagNames, f.Name)
})
if err := fs.Parse([]string{"--bool_value", "--struct_value", "sv", "-x"}); err != nil {
panic(err)
}
var got T
if err := sc.FromFlags(&got, fs); err != nil {
panic(err)
}
sort.Strings(flagNames)
fmt.Println(strings.Join(flagNames, ","))
fmt.Println(got.B, got.S, got.Ignore1, got.Ignore2, got.V.S, got.X)
}
Output: bool_short,bool_value,string_value,struct_value true str 0 0 sv true
Example (Prefix) ¶
package main
import (
"fmt"
"sort"
"strings"
"github.com/berquerant/structconfig"
"github.com/spf13/pflag"
)
func main() {
tagPrefix := "sc"
type T struct {
B bool `scname:"bool_value" scusage:"BOOL"`
S string `scname:"string_value" scdefault:"str"`
}
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
sc := structconfig.New[T](structconfig.WithPrefix(tagPrefix))
if err := sc.SetFlags(fs); err != nil {
panic(err)
}
flagNames := []string{}
fs.VisitAll(func(f *pflag.Flag) {
flagNames = append(flagNames, f.Name)
})
if err := fs.Parse([]string{"--bool_value", "--string_value", "sv"}); err != nil {
panic(err)
}
var got T
if err := sc.FromFlags(&got, fs); err != nil {
panic(err)
}
sort.Strings(flagNames)
fmt.Println(strings.Join(flagNames, ","))
fmt.Println(got.B, got.S)
}
Output: bool_value,string_value true sv
type StructField ¶
type StructField = internal.StructField
type UintReceptor ¶
type UintReceptor = internal.UintReceptor