Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

split file and fs provider #49

Merged
merged 9 commits into from
Nov 12, 2023
Merged
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
4 changes: 4 additions & 0 deletions .github/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ component_management:
- component_id: konf
paths:
- "!provider/pflag/"
- "!provider/file/"
- component_id: file
paths:
- "provider/file/"
- component_id: pflag
paths:
- "provider/pflag/"
5 changes: 5 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ updates:
schedule:
interval: daily

- package-ecosystem: gomod
directory: /provider/file
schedule:
interval: daily

- package-ecosystem: gomod
directory: /provider/pflag
schedule:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ jobs:
go-version: 'stable'
- name: Benchmark
run: go test -v -shuffle=on -bench=. ./...
- name: Benchmark (file)
run: go test -v -shuffle=on -bench=. ./...
working-directory: provider/file
- name: Benchmark (pflag)
run: go test -v -shuffle=on -bench=. ./...
working-directory: provider/pflag
3 changes: 3 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ jobs:
go-version: 'stable'
- name: Coverage
run: go test -v -covermode=count -coverprofile=coverage.txt ./...
- name: Coverage (file)
run: go test -v -covermode=count -coverprofile=coverage.txt ./...
working-directory: provider/file
- name: Coverage (pflag)
run: go test -v -covermode=count -coverprofile=coverage.txt ./...
working-directory: provider/pflag
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ jobs:
go-version: 'stable'
- name: Lint
uses: golangci/golangci-lint-action@v3
- name: Lint (file)
uses: golangci/golangci-lint-action@v3
with:
working-directory: provider/file
- name: Lint (pflag)
uses: golangci/golangci-lint-action@v3
with:
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ jobs:
run: go test -v -shuffle=on -count=10 -race ./...
- name: Test
run: go test -v -shuffle=on ./...
- name: Race Test (file)
run: go test -v -shuffle=on -count=10 -race ./...
working-directory: provider/file
- name: Test (file)
run: go test -v -shuffle=on ./...
working-directory: provider/file
- name: Race Test (pflag)
run: go test -v -shuffle=on -count=10 -race ./...
working-directory: provider/pflag
Expand Down
9 changes: 1 addition & 8 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,6 @@ linters-settings:
local-prefixes: github.com/ktong/konf
govet:
check-shadowing: true
ireturn:
allow:
- anon
- error
- empty
- stdlib
- T
makezero:
always: true
misspell:
Expand Down Expand Up @@ -86,7 +79,7 @@ linters:
- govet
- grouper
- importas
# inamedparam
- inamedparam
- ineffassign
- interfacebloat
- ireturn
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed

- Split file and fs provider (#49).

### Removed

- Remove konf.Logger in favor of slog (#48).
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ There are providers for the following configuration sources:
- `env` loads configuration from environment variables.
- `file` loads configuration from a file.
- `flag` loads configuration from flags.
- `fs` loads configuration from fs.FS.
- `pflag` loads configuration from [spf13/pflag](https://github.com/spf13/pflag).

## Compatibility
Expand Down
11 changes: 6 additions & 5 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
type Config struct {
delimiter string

values map[string]any
values *provider
providers []*provider
watchOnce sync.Once
}
Expand All @@ -29,6 +29,7 @@ type Config struct {
func New(opts ...Option) (*Config, error) {
option := apply(opts)
config := option.Config
config.values = &provider{values: make(map[string]any)}
config.providers = make([]*provider, 0, len(option.loaders))

for _, loader := range option.loaders {
Expand All @@ -44,7 +45,7 @@ func New(opts ...Option) (*Config, error) {
if err != nil {
return nil, fmt.Errorf("[konf] load configuration: %w", err)
}
maps.Merge(config.values, values)
maps.Merge(config.values.values, values)
slog.Info(
"Configuration has been loaded.",
"loader", loader,
Expand Down Expand Up @@ -92,10 +93,10 @@ func (c *Config) Unmarshal(path string, target any) error {

func (c *Config) sub(path string) any {
if path == "" {
return c.values
return c.values.values
}

var next any = c.values
var next any = c.values.values
for _, key := range strings.Split(strings.ToLower(path), c.delimiter) {
mp, ok := next.(map[string]any)
if !ok {
Expand Down Expand Up @@ -142,7 +143,7 @@ func (c *Config) Watch(ctx context.Context, fns ...func(*Config)) error { //noli
for _, w := range c.providers {
maps.Merge(values, w.values)
}
c.values = values
c.values.values = values

for _, fn := range fns {
fn(c)
Expand Down
21 changes: 0 additions & 21 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"testing"

"github.com/stretchr/testify/require"
"golang.org/x/sync/errgroup"

"github.com/ktong/konf"
)
Expand Down Expand Up @@ -179,26 +178,6 @@ func TestConfig_Watch(t *testing.T) {
require.Equal(t, "changed", cfg)
}

func TestConfig_Watch_twice(t *testing.T) {
t.Parallel()

config, err := konf.New(konf.WithLoader(mapWatcher(make(chan map[string]any))))
require.NoError(t, err)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

group, ctx := errgroup.WithContext(ctx)
group.Go(func() error {
return config.Watch(ctx)
})
group.Go(func() error {
return config.Watch(ctx)
})

require.EqualError(t, group.Wait(), "[konf] Watch only can be called once")
}

type mapWatcher chan map[string]any

func (m mapWatcher) Load() (map[string]any, error) {
Expand Down
28 changes: 2 additions & 26 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@
package konf_test

import (
"context"
"embed"
"fmt"
"time"

"golang.org/x/sync/errgroup"

"github.com/ktong/konf"
"github.com/ktong/konf/provider/env"
"github.com/ktong/konf/provider/file"
pfs "github.com/ktong/konf/provider/fs"
)

func ExampleGet() {
Expand Down Expand Up @@ -42,33 +38,13 @@ func ExampleUnmarshal() {
// Output: example.com:8080
}

func ExampleWatch() {
ExampleSetGlobal()

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

group, ctx := errgroup.WithContext(ctx)
group.Go(func() error {
return konf.Watch(ctx, func() {
fmt.Print(konf.Get[string]("server.host"))
})
})

if err := group.Wait(); err != nil {
// Handle error here.
panic(err)
}
// Output:
}

//go:embed testdata
var testdata embed.FS

func ExampleSetGlobal() {
cfg, err := konf.New(
konf.WithLoader(
file.New("testdata/config.json", file.WithFS(testdata)),
pfs.New(testdata, "testdata/config.json"),
env.New(env.WithPrefix("server")),
),
)
Expand Down
7 changes: 1 addition & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,16 @@ module github.com/ktong/konf

go 1.21

require (
github.com/fsnotify/fsnotify v1.7.0
github.com/mitchellh/mapstructure v1.5.0
)
require github.com/mitchellh/mapstructure v1.5.0

require ( // for test
github.com/stretchr/testify v1.8.4
go.uber.org/goleak v1.3.0
golang.org/x/sync v0.5.0
)

require ( // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
8 changes: 2 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
Expand All @@ -14,11 +13,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
1 change: 0 additions & 1 deletion option.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ func apply(opts []Option) options {
option := &options{
Config: &Config{
delimiter: ".",
values: make(map[string]any),
},
}
for _, opt := range opts {
Expand Down
14 changes: 7 additions & 7 deletions provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "context"

// Loader is the interface that wraps the Load method.
//
// Load loads configuration and returns as a nested map[string]any.
// Load loads latest configuration and returns as a nested map[string]any.
// It requires that the string keys should be nested like `{parent: {child: {key: 1}}}`.
// The key in returned map should be case-insensitive, otherwise random overridden exists.
type Loader interface {
Expand All @@ -16,17 +16,17 @@ type Loader interface {

// Watcher is the interface that wraps the Watch method.
//
// Watch watches configuration and triggers a callback with full new configurations
// as a nested map[string]any when it changes.
// It blocks until ctx is done, or the service returns an error.
// Watch watches configuration and triggers onChange callback with latest
// full configurations as a nested map[string]any when it changes.
// It blocks until ctx is done, or the watching returns an error.
type Watcher interface {
Watch(context.Context, func(map[string]any)) error
Watch(ctx context.Context, onChange func(map[string]any)) error
}

// ConfigAware is the interface that wraps the WithConfig method.
//
// WithConfig enables provider loads configuration from providers before it.
// WithConfig enables provider uses configuration loaded by providers before it.
// It ensures the WithConfig is called before executing methods in Loader and Watcher.
type ConfigAware interface {
WithConfig(*Config)
WithConfig(config *Config)
}
17 changes: 2 additions & 15 deletions provider/file/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,16 @@ package file_test

import (
"testing"
"testing/fstest"

"github.com/stretchr/testify/require"

"github.com/ktong/konf/provider/file"
)

func BenchmarkNew(b *testing.B) {
mapFS := fstest.MapFS{
"config.json": {
Data: []byte(`{"k":"v"}`),
},
}
b.ResetTimer()

var loader file.File
for i := 0; i < b.N; i++ {
loader = file.New("config.json", file.WithFS(mapFS))
loader = file.New("testdata/config.json")
}
b.StopTimer()

Expand All @@ -32,12 +24,7 @@ func BenchmarkNew(b *testing.B) {
}

func BenchmarkLoad(b *testing.B) {
fs := fstest.MapFS{
"config.json": {
Data: []byte(`{"k":"v"}`),
},
}
loader := file.New("config.json", file.WithFS(fs))
loader := file.New("testdata/config.json")
b.ResetTimer()

var (
Expand Down
Loading
Loading