add toml provider #7

Merged
andrey merged 1 commits from toml into master 9 months ago
  1. 19
      .drone.yml
  2. 31
      provider/toml/fixture/config.toml
  3. 15
      provider/toml/go.mod
  4. 14
      provider/toml/go.sum
  5. 71
      provider/toml/provider.go
  6. 36
      provider/toml/provider_test.go
  7. 41
      provider/toml/value.go

19
.drone.yml

@ -72,3 +72,22 @@ steps:
- cd provider/ini
- golangci-lint run
---
kind: pipeline
type: docker
name: toml
steps:
- name: test
image: golang
commands:
- cd provider/toml
- go test ./...
- name: golangci-lint
image: golangci/golangci-lint:v1.55
commands:
- cd provider/toml
- golangci-lint run

31
provider/toml/fixture/config.toml

@ -0,0 +1,31 @@
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # First class dates
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# Indentation (tabs and/or spaces) is allowed but not required
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[clients]
data = [ ["gamma", "delta"], [1, 2] ]
# Line breaks are OK when inside arrays
hosts = [
"alpha",
"omega"
]

15
provider/toml/go.mod

@ -0,0 +1,15 @@
module gitoa.ru/go-4devs/config/provider/toml
go 1.21
require (
github.com/pelletier/go-toml v1.9.5
github.com/stretchr/testify v1.8.4
gitoa.ru/go-4devs/config v0.0.1
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

14
provider/toml/go.sum

@ -0,0 +1,14 @@
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/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gitoa.ru/go-4devs/config v0.0.1 h1:9KrOO09YbIMO8qL8aVn/G74DurGdOIW5y3O02bays4I=
gitoa.ru/go-4devs/config v0.0.1/go.mod h1:xfEC2Al9xnMLJUuekYs3KhJ5BIzWAseNwkMwbN6/xss=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=

71
provider/toml/provider.go

@ -0,0 +1,71 @@
package toml
import (
"context"
"fmt"
"strings"
"github.com/pelletier/go-toml"
"gitoa.ru/go-4devs/config"
"gitoa.ru/go-4devs/config/value"
)
const (
Name = "toml"
Separator = "."
)
var _ config.Provider = (*Provider)(nil)
func NewFile(file string, opts ...Option) (*Provider, error) {
tree, err := toml.LoadFile(file)
if err != nil {
return nil, fmt.Errorf("toml: failed load file: %w", err)
}
return configure(tree, opts...), nil
}
type Option func(*Provider)
func configure(tree *toml.Tree, opts ...Option) *Provider {
prov := &Provider{
tree: tree,
key: func(s []string) string {
return strings.Join(s, Separator)
},
}
for _, opt := range opts {
opt(prov)
}
return prov
}
func New(data []byte, opts ...Option) (*Provider, error) {
tree, err := toml.LoadBytes(data)
if err != nil {
return nil, fmt.Errorf("toml failed load data: %w", err)
}
return configure(tree, opts...), nil
}
type Provider struct {
tree *toml.Tree
key func([]string) string
name string
}
func (p *Provider) Name() string {
return p.name
}
func (p *Provider) Value(_ context.Context, path ...string) (config.Value, error) {
if k := p.key(path); p.tree.Has(k) {
return Value{Value: value.Value{Val: p.tree.Get(k)}}, nil
}
return nil, config.ErrValueNotFound
}

36
provider/toml/provider_test.go

@ -0,0 +1,36 @@
package toml_test
import (
"embed"
"testing"
"gitoa.ru/go-4devs/config/provider/toml"
"gitoa.ru/go-4devs/config/test"
"gitoa.ru/go-4devs/config/test/require"
)
//go:embed fixture/*
var fixtures embed.FS
func TestProvider(t *testing.T) {
t.Parallel()
files, ferr := fixtures.ReadFile("fixture/config.toml")
require.NoError(t, ferr)
prov, err := toml.New(files)
require.NoError(t, err)
m := []int{}
read := []test.Read{
test.NewRead("192.168.1.1", "database.server"),
test.NewRead("TOML Example", "title"),
test.NewRead("10.0.0.1", "servers.alpha.ip"),
test.NewRead(true, "database.enabled"),
test.NewRead(5000, "database.connection_max"),
test.NewReadUnmarshal(&[]int{8001, 8001, 8002}, &m, "database", "ports"),
}
test.Run(t, prov, read)
}

41
provider/toml/value.go

@ -0,0 +1,41 @@
package toml
import (
"encoding/json"
"fmt"
"gitoa.ru/go-4devs/config"
"gitoa.ru/go-4devs/config/value"
)
type Value struct {
value.Value
}
func (s Value) Int() int {
v, _ := s.ParseInt()
return v
}
func (s Value) ParseInt() (int, error) {
v, err := s.ParseInt64()
if err != nil {
return 0, fmt.Errorf("toml failed parce int: %w", err)
}
return int(v), nil
}
func (s Value) Unmarshal(target interface{}) error {
b, err := json.Marshal(s.Raw())
if err != nil {
return fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
if err := json.Unmarshal(b, target); err != nil {
return fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return nil
}
Loading…
Cancel
Save