Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ go get -u github.com/knadh/koanf/parsers/toml

### Concepts

- `koanf.Provider` is a generic interface that provides configuration, for example, from files, environment variables, HTTP sources, or anywhere. The configuration can either be raw bytes that a parser can parse, or it can be a nested `map[string]interface{}` that can be directly loaded.
- `koanf.Parser` is a generic interface that takes raw bytes, parses, and returns a nested `map[string]interface{}`. For example, JSON and YAML parsers.
- `koanf.Provider` is a generic interface that provides configuration, for example, from files, environment variables, HTTP sources, or anywhere. The configuration can either be raw bytes that a parser can parse, or it can be a nested `map[string]any` that can be directly loaded.
- `koanf.Parser` is a generic interface that takes raw bytes, parses, and returns a nested `map[string]any`. For example, JSON and YAML parsers.
- Once loaded into koanf, configuration are values queried by a delimited key path syntax. eg: `app.server.port`. Any delimiter can be chosen.
- Configuration from multiple sources can be loaded and merged into a koanf instance, for example, load from a file first and override certain values with flags from the command line.

Expand Down Expand Up @@ -133,7 +133,7 @@ func main() {
// Watch the file and get a callback on change. The callback can do whatever,
// like re-load the configuration.
// File provider always returns a nil `event`.
f.Watch(func(event interface{}, err error) {
f.Watch(func(event any, err error) {
if err != nil {
log.Printf("watch error: %v", err)
return
Expand Down Expand Up @@ -430,7 +430,7 @@ func main() {

#### Reading from nested maps

The bundled `confmap` provider takes a `map[string]interface{}` that can be loaded into a koanf instance.
The bundled `confmap` provider takes a `map[string]any` that can be loaded into a koanf instance.

```go
package main
Expand All @@ -453,7 +453,7 @@ func main() {
// Load default values using the confmap provider.
// We provide a flat map with the "." delimiter.
// A nested map can be loaded by setting the delimiter to an empty string "".
k.Load(confmap.Provider(map[string]interface{}{
k.Load(confmap.Provider(map[string]any{
"parent1.name": "Default Name",
"parent3.name": "New name here",
}, "."), nil)
Expand Down Expand Up @@ -596,11 +596,11 @@ For example: merging JSON and YAML will most likely fail because JSON treats int

### Custom Providers and Parsers

A Provider returns a nested `map[string]interface{}` config that can be loaded directly into koanf with `koanf.Load()` or it can return raw bytes that can be parsed with a Parser (again, loaded using `koanf.Load()`. Writing Providers and Parsers are easy. See the bundled implementations in the [providers](https://github.com/knadh/koanf/tree/master/providers) and [parsers](https://github.com/knadh/koanf/tree/master/parsers) directories.
A Provider returns a nested `map[string]any` config that can be loaded directly into koanf with `koanf.Load()` or it can return raw bytes that can be parsed with a Parser (again, loaded using `koanf.Load()`. Writing Providers and Parsers are easy. See the bundled implementations in the [providers](https://github.com/knadh/koanf/tree/master/providers) and [parsers](https://github.com/knadh/koanf/tree/master/parsers) directories.

### Custom merge strategies

By default, when merging two config sources using `Load()`, koanf recursively merges keys of nested maps (`map[string]interface{}`),
By default, when merging two config sources using `Load()`, koanf recursively merges keys of nested maps (`map[string]any`),
while static values are overwritten (slices, strings, etc). This behaviour can be changed by providing a custom merge function with the `WithMergeFunc` option.

```go
Expand Down Expand Up @@ -630,7 +630,7 @@ func main() {
}

jsonPath := "mock/mock.json"
if err := k.Load(file.Provider(jsonPath), json.Parser(), koanf.WithMergeFunc(func(src, dest map[string]interface{}) error {
if err := k.Load(file.Provider(jsonPath), json.Parser(), koanf.WithMergeFunc(func(src, dest map[string]any) error {
// Your custom logic, copying values from src into dst
return nil
})); err != nil {
Expand All @@ -654,8 +654,8 @@ Install with `go get -u github.com/knadh/koanf/providers/$provider`
| basicflag | `basicflag.Provider(f *flag.FlagSet, delim string)` | Takes a stdlib `flag.FlagSet` |
| posflag | `posflag.Provider(f *pflag.FlagSet, delim string)` | Takes an `spf13/pflag.FlagSet` (advanced POSIX compatible flags with multiple types) and provides a nested config map based on delim. |
| env/v2 | `env.Provider(prefix, delim string, f func(s string) string)` | Takes an optional prefix to filter env variables by, an optional function that takes and returns a string to transform env variables, and returns a nested config map based on delim. |
| confmap | `confmap.Provider(mp map[string]interface{}, delim string)` | Takes a premade `map[string]interface{}` conf map. If delim is provided, the keys are assumed to be flattened, thus unflattened using delim. |
| structs | `structs.Provider(s interface{}, tag string)` | Takes a struct and struct tag. |
| confmap | `confmap.Provider(mp map[string]any, delim string)` | Takes a premade `map[string]any` conf map. If delim is provided, the keys are assumed to be flattened, thus unflattened using delim. |
| structs | `structs.Provider(s any, tag string)` | Takes a struct and struct tag. |
| s3 | `s3.Provider(s3.S3Config{})` | Takes a s3 config struct. |
| rawbytes | `rawbytes.Provider(b []byte)` | Takes a raw `[]byte` slice to be parsed with a koanf.Parser |
| vault/v2 | `vault.Provider(vault.Config{})` | Hashicorp Vault provider |
Expand Down
2 changes: 1 addition & 1 deletion examples/complex-etcd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ func main() {

changedC := make(chan string, 1)

provider.Watch(func(event interface{}, err error) {
provider.Watch(func(event any, err error) {
if err != nil {
fmt.Printf("Unexpected error: %v", err)
return
Expand Down
4 changes: 2 additions & 2 deletions examples/default-values/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import (
"fmt"
"log"

"github.com/knadh/koanf/v2"
"github.com/knadh/koanf/parsers/json"
"github.com/knadh/koanf/parsers/yaml"
"github.com/knadh/koanf/providers/confmap"
"github.com/knadh/koanf/providers/file"
"github.com/knadh/koanf/v2"
)

// Global koanf instance. Use "." as the key path delimiter. This can be "/" or any character.
Expand All @@ -18,7 +18,7 @@ func main() {
// Load default values using the confmap provider.
// We provide a flat map with the "." delimiter.
// A nested map can be loaded by setting the delimiter to an empty string "".
k.Load(confmap.Provider(map[string]interface{}{
k.Load(confmap.Provider(map[string]any{
"parent1.name": "Default Name",
"parent3.name": "New name here",
}, "."), nil)
Expand Down
2 changes: 1 addition & 1 deletion examples/read-appconfig/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func main() {
k.Print()

// Watch for all configuration updates.
provider.Watch(func(event interface{}, err error) {
provider.Watch(func(event any, err error) {
if err != nil {
log.Printf("watch error: %v", err)
return
Expand Down
2 changes: 1 addition & 1 deletion examples/read-consul/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ func main() {

changedC := make(chan string, 1)

provider.Watch(func(event interface{}, err error) {
provider.Watch(func(event any, err error) {
if err != nil {
fmt.Printf("Unexpected error: %v", err)
return
Expand Down
2 changes: 1 addition & 1 deletion examples/read-file/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func main() {
// Watch the file and get a callback on change. The callback can do whatever,
// like re-load the configuration.
// File provider always returns a nil `event`.
f.Watch(func(event interface{}, err error) {
f.Watch(func(event any, err error) {
if err != nil {
log.Printf("watch error: %v", err)
return
Expand Down
24 changes: 12 additions & 12 deletions getters.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (ko *Koanf) Int64s(path string) []int64 {
out = append(out, i)
}
return out
case []interface{}:
case []any:
out = make([]int64, 0, len(v))
for _, vi := range v {
i, err := toInt64(vi)
Expand Down Expand Up @@ -91,7 +91,7 @@ func (ko *Koanf) Int64Map(path string) map[string]int64 {
return out
}

mp, ok := o.(map[string]interface{})
mp, ok := o.(map[string]any)
if !ok {
return out
}
Expand Down Expand Up @@ -158,7 +158,7 @@ func (ko *Koanf) Ints(path string) []int {
out = append(out, int(vi))
}
return out
case []interface{}:
case []any:
out = make([]int, 0, len(v))
for _, vi := range v {
i, err := toInt64(vi)
Expand Down Expand Up @@ -243,7 +243,7 @@ func (ko *Koanf) Float64s(path string) []float64 {
switch v := o.(type) {
case []float64:
return v
case []interface{}:
case []any:
out = make([]float64, 0, len(v))
for _, vi := range v {
i, err := toFloat64(vi)
Expand Down Expand Up @@ -283,7 +283,7 @@ func (ko *Koanf) Float64Map(path string) map[string]float64 {
return out
}

mp, ok := o.(map[string]interface{})
mp, ok := o.(map[string]any)
if !ok {
return out
}
Expand Down Expand Up @@ -402,7 +402,7 @@ func (ko *Koanf) Strings(path string) []string {

var out []string
switch v := o.(type) {
case []interface{}:
case []any:
out = make([]string, 0, len(v))
for _, u := range v {
if s, ok := u.(string); ok {
Expand Down Expand Up @@ -449,7 +449,7 @@ func (ko *Koanf) StringMap(path string) map[string]string {
for k, v := range mp {
out[k] = v
}
case map[string]interface{}:
case map[string]any:
out = make(map[string]string, len(mp))
for k, v := range mp {
switch s := v.(type) {
Expand Down Expand Up @@ -493,7 +493,7 @@ func (ko *Koanf) StringsMap(path string) map[string][]string {
for k, v := range mp {
out[k] = append(out[k], v...)
}
case map[string][]interface{}:
case map[string][]any:
out = make(map[string][]string, len(mp))
for k, v := range mp {
for _, v := range v {
Expand All @@ -505,13 +505,13 @@ func (ko *Koanf) StringsMap(path string) map[string][]string {
}
}
}
case map[string]interface{}:
case map[string]any:
out = make(map[string][]string, len(mp))
for k, v := range mp {
switch s := v.(type) {
case []string:
out[k] = append(out[k], s...)
case []interface{}:
case []any:
for _, v := range s {
switch sv := v.(type) {
case string:
Expand Down Expand Up @@ -578,7 +578,7 @@ func (ko *Koanf) Bools(path string) []bool {

var out []bool
switch v := o.(type) {
case []interface{}:
case []any:
out = make([]bool, 0, len(v))
for _, u := range v {
b, err := toBool(u)
Expand Down Expand Up @@ -616,7 +616,7 @@ func (ko *Koanf) BoolMap(path string) map[string]bool {
return out
}

mp, ok := o.(map[string]interface{})
mp, ok := o.(map[string]any)
if !ok {
return out
}
Expand Down
8 changes: 4 additions & 4 deletions interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ type Provider interface {
// with a Parser.
ReadBytes() ([]byte, error)

// Read returns the parsed configuration as a nested map[string]interface{}.
// Read returns the parsed configuration as a nested map[string]any.
// It is important to note that the string keys should not be flat delimited
// keys like `parent.child.key`, but nested like `{parent: {child: {key: 1}}}`.
Read() (map[string]interface{}, error)
Read() (map[string]any, error)
}

// Parser represents a configuration format parser.
type Parser interface {
Unmarshal([]byte) (map[string]interface{}, error)
Marshal(map[string]interface{}) ([]byte, error)
Unmarshal([]byte) (map[string]any, error)
Marshal(map[string]any) ([]byte, error)
}
Loading
Loading