Browse Source

update golangci

pull/2/head
andrey1s 11 months ago
parent
commit
d839e1ac90
  1. 2
      .drone.yml
  2. 18
      .golangci.yml
  3. 30
      client.go
  4. 4
      client_example_test.go
  5. 8
      key/helpers.go
  6. 52
      provider/arg/provider.go
  7. 17
      provider/env/provider.go
  8. 16
      provider/etcd/provider.go
  9. 8
      provider/ini/provider.go
  10. 2
      provider/json/provider.go
  11. 6
      provider/toml/provider.go
  12. 4
      provider/toml/value.go
  13. 22
      provider/vault/secret.go
  14. 6
      provider/watcher/provider.go
  15. 7
      provider/watcher/provider_test.go
  16. 22
      provider/yaml/provider.go
  17. 6
      provider/yaml/watch.go
  18. 1
      value/decode.go
  19. 2
      value/empty.go
  20. 16
      value/helpers.go
  21. 2
      value/value.go

2
.drone.yml

@ -24,6 +24,6 @@ steps:
- go test -parallel 10 -race ./...
- name: golangci-lint
image: golangci/golangci-lint:v1.39
image: golangci/golangci-lint:v1.53
commands:
- golangci-lint run

18
.golangci.yml

@ -22,6 +22,8 @@ linters-settings:
suggest-new: true
misspell:
locale: US
varnamelen:
min-name-length: 2
linters:
enable-all: true
@ -30,6 +32,16 @@ linters:
- maligned
- interfacer
- scopelint
- exhaustruct
- depguard
- nolintlint
#deprecated
- structcheck
- varcheck
- golint
- deadcode
- ifshort
- nosnakecase
issues:
# Excluding configuration per-path, per-linter, per-text and per-source
@ -39,8 +51,14 @@ issues:
- gomnd
- exhaustivestruct
- wrapcheck
- exhaustruct
- varnamelen
- tenv
- funlen
- path: test/*
linters:
- gomnd
- exhaustivestruct
- wrapcheck
- exhaustruct
- varnamelen

30
client.go

@ -49,17 +49,21 @@ type provider struct {
factory func(ctx context.Context) (Provider, error)
}
func (p *provider) init(ctx context.Context) (err error) {
func (p *provider) init(ctx context.Context) error {
if atomic.LoadUint32(&p.done) == 0 {
if !p.mu.TryLock() {
return fmt.Errorf("%w", ErrInitFactory)
}
defer atomic.StoreUint32(&p.done, 1)
defer p.mu.Unlock()
p.provider, err = p.factory(ctx)
var err error
if p.provider, err = p.factory(ctx); err != nil {
return fmt.Errorf("init provider factory:%w", err)
}
}
return err
return nil
}
func (p *provider) Watch(ctx context.Context, key Key, callback WatchCallback) error {
@ -67,8 +71,13 @@ func (p *provider) Watch(ctx context.Context, key Key, callback WatchCallback) e
return fmt.Errorf("init read:%w", err)
}
if watch, ok := p.provider.(WatchProvider); ok {
return watch.Watch(ctx, key, callback)
watch, ok := p.provider.(WatchProvider)
if !ok {
return nil
}
if err := watch.Watch(ctx, key, callback); err != nil {
return fmt.Errorf("factory provider: %w", err)
}
return nil
@ -79,7 +88,12 @@ func (p *provider) Read(ctx context.Context, key Key) (Variable, error) {
return Variable{}, fmt.Errorf("init read:%w", err)
}
return p.provider.Read(ctx, key)
variable, err := p.provider.Read(ctx, key)
if err != nil {
return Variable{}, fmt.Errorf("factory provider: %w", err)
}
return variable, nil
}
type Client struct {
@ -96,10 +110,12 @@ func (c *Client) key(name string) Key {
}
}
// Value get value by name.
// nolint: ireturn
func (c *Client) Value(ctx context.Context, name string) (Value, error) {
variable, err := c.Variable(ctx, name)
if err != nil {
return nil, err
return nil, fmt.Errorf("variable:%w", err)
}
return variable.Value, nil

4
client_example_test.go

@ -284,11 +284,11 @@ func ExampleClient_Value_factory() {
fmt.Printf("listen from env: %d\n", port.Int())
fmt.Printf("title from json: %v\n", title.String())
fmt.Printf("title from yaml: %v\n", yamlTitle.String())
fmt.Printf("yaml title: %v\n", yamlTitle.String())
fmt.Printf("struct from json: %+v\n", cfg)
// Output:
// listen from env: 8080
// title from json: config title
// title from yaml: yaml title
// yaml title: yaml title
// struct from json: {Duration:21m0s Enabled:true}
}

8
key/helpers.go

@ -9,14 +9,14 @@ import (
func LastIndex(sep string, factory config.KeyFactory) func(ctx context.Context, key config.Key) (string, string) {
return func(ctx context.Context, key config.Key) (string, string) {
k := factory(ctx, key)
name := factory(ctx, key)
idx := strings.LastIndex(k, sep)
idx := strings.LastIndex(name, sep)
if idx == -1 {
return k, ""
return name, ""
}
return k[0:idx], k[idx+len(sep):]
return name[0:idx], name[idx+len(sep):]
}
}

52
provider/arg/provider.go

@ -21,15 +21,16 @@ func WithKeyFactory(factory config.KeyFactory) Option {
}
func New(opts ...Option) *Provider {
p := Provider{
key: key.Name,
prov := Provider{
key: key.Name,
args: make(map[string][]string, len(os.Args[1:])),
}
for _, opt := range opts {
opt(&p)
opt(&prov)
}
return &p
return &prov
}
type Provider struct {
@ -38,9 +39,10 @@ type Provider struct {
}
// nolint: cyclop
func (p *Provider) parseOne(arg string) (name, val string, err error) {
// return name, value, error.
func (p *Provider) parseOne(arg string) (string, string, error) {
if arg[0] != '-' {
return
return "", "", nil
}
numMinuses := 1
@ -49,19 +51,21 @@ func (p *Provider) parseOne(arg string) (name, val string, err error) {
numMinuses++
}
name = strings.TrimSpace(arg[numMinuses:])
name := strings.TrimSpace(arg[numMinuses:])
if len(name) == 0 {
return
return name, "", nil
}
if name[0] == '-' || name[0] == '=' {
return "", "", fmt.Errorf("%w: bad flag syntax: %s", config.ErrInvalidValue, arg)
}
for i := 1; i < len(name); i++ {
if name[i] == '=' || name[i] == ' ' {
val = strings.TrimSpace(name[i+1:])
name = name[0:i]
var val string
for idx := 1; idx < len(name); idx++ {
if name[idx] == '=' || name[idx] == ' ' {
val = strings.TrimSpace(name[idx+1:])
name = name[0:idx]
break
}
@ -79,8 +83,6 @@ func (p *Provider) parse() error {
return nil
}
p.args = make(map[string][]string, len(os.Args[1:]))
for _, arg := range os.Args[1:] {
name, value, err := p.parseOne(arg)
if err != nil {
@ -105,32 +107,36 @@ func (p *Provider) IsSupport(ctx context.Context, key config.Key) bool {
func (p *Provider) Read(ctx context.Context, key config.Key) (config.Variable, error) {
if err := p.parse(); err != nil {
return config.Variable{Provider: p.Name()}, err
return config.Variable{
Name: "",
Value: nil,
Provider: p.Name(),
}, err
}
k := p.key(ctx, key)
if val, ok := p.args[k]; ok {
name := p.key(ctx, key)
if val, ok := p.args[name]; ok {
switch {
case len(val) == 1:
return config.Variable{
Name: k,
Name: name,
Provider: p.Name(),
Value: value.JString(val[0]),
}, nil
default:
var n yaml.Node
var yNode yaml.Node
if err := yaml.Unmarshal([]byte("["+strings.Join(val, ",")+"]"), &n); err != nil {
if err := yaml.Unmarshal([]byte("["+strings.Join(val, ",")+"]"), &yNode); err != nil {
return config.Variable{}, fmt.Errorf("arg: failed unmarshal yaml:%w", err)
}
return config.Variable{
Name: k,
Name: name,
Provider: p.Name(),
Value: value.Decode(n.Decode),
Value: value.Decode(yNode.Decode),
}, nil
}
}
return config.Variable{Name: k, Provider: p.Name()}, config.ErrVariableNotFound
return config.Variable{}, fmt.Errorf("%w: %s", config.ErrVariableNotFound, name)
}

17
provider/env/provider.go

@ -19,17 +19,17 @@ func WithKeyFactory(factory config.KeyFactory) Option {
}
func New(opts ...Option) *Provider {
p := Provider{
provider := Provider{
key: func(ctx context.Context, k config.Key) string {
return strings.ToUpper(key.NsAppName("_")(ctx, k))
},
}
for _, opt := range opts {
opt(&p)
opt(&provider)
}
return &p
return &provider
}
type Provider struct {
@ -45,17 +45,14 @@ func (p *Provider) IsSupport(ctx context.Context, key config.Key) bool {
}
func (p *Provider) Read(ctx context.Context, key config.Key) (config.Variable, error) {
k := p.key(ctx, key)
if val, ok := os.LookupEnv(k); ok {
name := p.key(ctx, key)
if val, ok := os.LookupEnv(name); ok {
return config.Variable{
Name: k,
Name: name,
Provider: p.Name(),
Value: value.JString(val),
}, nil
}
return config.Variable{
Name: k,
Provider: p.Name(),
}, config.ErrVariableNotFound
return config.Variable{}, config.ErrVariableNotFound
}

16
provider/etcd/provider.go

@ -44,16 +44,16 @@ func (p *Provider) Name() string {
}
func (p *Provider) Read(ctx context.Context, key config.Key) (config.Variable, error) {
k := p.key(ctx, key)
name := p.key(ctx, key)
resp, err := p.client.Get(ctx, k, client.WithPrefix())
resp, err := p.client.Get(ctx, name, client.WithPrefix())
if err != nil {
return config.Variable{}, fmt.Errorf("%w: key:%s, prov:%s", err, k, p.Name())
return config.Variable{}, fmt.Errorf("%w: key:%s, prov:%s", err, name, p.Name())
}
val, err := p.resolve(k, resp.Kvs)
val, err := p.resolve(name, resp.Kvs)
if err != nil {
return config.Variable{}, fmt.Errorf("%w: key:%s, prov:%s", err, k, p.Name())
return config.Variable{}, fmt.Errorf("%w: key:%s, prov:%s", err, name, p.Name())
}
return val, nil
@ -94,6 +94,7 @@ func (p *Provider) resolve(key string, kvs []*pb.KeyValue) (config.Variable, err
return config.Variable{
Name: key,
Provider: p.Name(),
Value: nil,
}, nil
case string(kv.Key) == key:
return config.Variable{
@ -104,8 +105,5 @@ func (p *Provider) resolve(key string, kvs []*pb.KeyValue) (config.Variable, err
}
}
return config.Variable{
Name: key,
Provider: p.Name(),
}, config.ErrVariableNotFound
return config.Variable{}, fmt.Errorf("%w: name %s", config.ErrVariableNotFound, key)
}

8
provider/ini/provider.go

@ -13,10 +13,12 @@ import (
var _ config.Provider = (*Provider)(nil)
func New(data *ini.File) *Provider {
const nameParts = 2
return &Provider{
data: data,
resolve: func(ctx context.Context, key config.Key) (string, string) {
keys := strings.SplitN(key.Name, "/", 2)
keys := strings.SplitN(key.Name, "/", nameParts)
if len(keys) == 1 {
return "", keys[0]
}
@ -46,12 +48,12 @@ func (p *Provider) Read(ctx context.Context, key config.Key) (config.Variable, e
iniSection, err := p.data.GetSection(section)
if err != nil {
return config.Variable{}, fmt.Errorf("%w: %s: %v", config.ErrVariableNotFound, p.Name(), err)
return config.Variable{}, fmt.Errorf("%w: %s: %w", config.ErrVariableNotFound, p.Name(), err)
}
iniKey, err := iniSection.GetKey(name)
if err != nil {
return config.Variable{}, fmt.Errorf("%w: %s: %v", config.ErrVariableNotFound, p.Name(), err)
return config.Variable{}, fmt.Errorf("%w: %s: %w", config.ErrVariableNotFound, p.Name(), err)
}
return config.Variable{

2
provider/json/provider.go

@ -33,7 +33,7 @@ func NewFile(path string, opts ...Option) (*Provider, error) {
return nil, fmt.Errorf("%w: unable to read config file %#q: file not found or unreadable", err, path)
}
return New(file), nil
return New(file, opts...), nil
}
type Option func(*Provider)

6
provider/toml/provider.go

@ -24,16 +24,16 @@ func NewFile(file string, opts ...Option) (*Provider, error) {
type Option func(*Provider)
func configure(tree *toml.Tree, opts ...Option) *Provider {
p := &Provider{
prov := &Provider{
tree: tree,
key: key.Name,
}
for _, opt := range opts {
opt(p)
opt(prov)
}
return p
return prov
}
func New(data []byte, opts ...Option) (*Provider, error) {

4
provider/toml/value.go

@ -30,11 +30,11 @@ func (s Value) ParseInt() (int, error) {
func (s Value) Unmarshal(target interface{}) error {
b, err := json.Marshal(s.Raw())
if err != nil {
return fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
if err := json.Unmarshal(b, target); err != nil {
return fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return nil

22
provider/vault/secret.go

@ -20,16 +20,16 @@ func WithSecretResolve(f func(context.Context, config.Key) (string, string)) Sec
}
func NewSecretKV2(client *api.Client, opts ...SecretOption) *SecretKV2 {
s := SecretKV2{
prov := SecretKV2{
client: client,
resolve: key.LastIndexField(":", "value", key.PrefixName("secret/data/", key.NsAppName("/"))),
}
for _, opt := range opts {
opt(&s)
opt(&prov)
}
return &s
return &prov
}
type SecretKV2 struct {
@ -50,26 +50,26 @@ func (p *SecretKV2) Name() string {
func (p *SecretKV2) Read(ctx context.Context, key config.Key) (config.Variable, error) {
path, field := p.resolve(ctx, key)
s, err := p.client.Logical().Read(path)
secret, err := p.client.Logical().Read(path)
if err != nil {
return config.Variable{}, fmt.Errorf("%w: path:%s, field:%s, provider:%s", err, path, field, p.Name())
}
if s == nil || len(s.Data) == 0 {
if secret == nil || len(secret.Data) == 0 {
return config.Variable{}, fmt.Errorf("%w: path:%s, field:%s, provider:%s", config.ErrVariableNotFound, path, field, p.Name())
}
if len(s.Warnings) > 0 {
if len(secret.Warnings) > 0 {
return config.Variable{},
fmt.Errorf("%w: warn: %s, path:%s, field:%s, provider:%s", config.ErrVariableNotFound, s.Warnings, path, field, p.Name())
fmt.Errorf("%w: warn: %s, path:%s, field:%s, provider:%s", config.ErrVariableNotFound, secret.Warnings, path, field, p.Name())
}
d, ok := s.Data["data"].(map[string]interface{})
data, ok := secret.Data["data"].(map[string]interface{})
if !ok {
return config.Variable{}, fmt.Errorf("%w: path:%s, field:%s, provider:%s", config.ErrVariableNotFound, path, field, p.Name())
}
if val, ok := d[field]; ok {
if val, ok := data[field]; ok {
return config.Variable{
Name: path + field,
Provider: p.Name(),
@ -77,9 +77,9 @@ func (p *SecretKV2) Read(ctx context.Context, key config.Key) (config.Variable,
}, nil
}
md, err := json.Marshal(d)
md, err := json.Marshal(data)
if err != nil {
return config.Variable{}, fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return config.Variable{}, fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return config.Variable{

6
provider/watcher/provider.go

@ -15,7 +15,7 @@ var (
)
func New(duration time.Duration, provider config.Provider, opts ...Option) *Provider {
p := &Provider{
prov := &Provider{
Provider: provider,
ticker: time.NewTicker(duration),
logger: func(_ context.Context, msg string) {
@ -24,10 +24,10 @@ func New(duration time.Duration, provider config.Provider, opts ...Option) *Prov
}
for _, opt := range opts {
opt(p)
opt(prov)
}
return p
return prov
}
func WithLogger(l func(context.Context, string)) Option {

7
provider/watcher/provider_test.go

@ -22,12 +22,13 @@ func (p *provider) Name() string {
return "test"
}
func (p *provider) Read(ctx context.Context, k config.Key) (config.Variable, error) {
func (p *provider) Read(context.Context, config.Key) (config.Variable, error) {
p.cnt++
return config.Variable{
Name: "tmpname",
Value: value.JString(fmt.Sprint(p.cnt)),
Name: "tmpname",
Provider: p.Name(),
Value: value.JString(fmt.Sprint(p.cnt)),
}, nil
}

22
provider/yaml/provider.go

@ -14,7 +14,7 @@ import (
var _ config.Provider = (*Provider)(nil)
func keyFactory(ctx context.Context, key config.Key) []string {
func keyFactory(_ context.Context, key config.Key) []string {
return strings.Split(key.Name, "/")
}
@ -37,15 +37,15 @@ func New(yml []byte, opts ...Option) (*Provider, error) {
}
func create(opts ...Option) *Provider {
p := Provider{
prov := Provider{
key: keyFactory,
}
for _, opt := range opts {
opt(&p)
opt(&prov)
}
return &p
return &prov
}
type Option func(*Provider)
@ -76,8 +76,8 @@ type node struct {
*yaml.Node
}
func (n *node) read(name string, k []string) (config.Variable, error) {
val, err := getData(n.Node.Content[0].Content, k)
func (n *node) read(name string, keys []string) (config.Variable, error) {
val, err := getData(n.Node.Content[0].Content, keys)
if err != nil {
if errors.Is(err, config.ErrVariableNotFound) {
return config.Variable{}, fmt.Errorf("%w: %s", config.ErrVariableNotFound, name)
@ -87,20 +87,20 @@ func (n *node) read(name string, k []string) (config.Variable, error) {
}
return config.Variable{
Name: strings.Join(k, "."),
Name: strings.Join(keys, "."),
Provider: name,
Value: value.Decode(val),
}, nil
}
func getData(node []*yaml.Node, keys []string) (func(interface{}) error, error) {
for i := len(node) - 1; i > 0; i -= 2 {
if node[i-1].Value == keys[0] {
for idx := len(node) - 1; idx > 0; idx -= 2 {
if node[idx-1].Value == keys[0] {
if len(keys) > 1 {
return getData(node[i].Content, keys[1:])
return getData(node[idx].Content, keys[1:])
}
return node[i].Decode, nil
return node[idx].Decode, nil
}
}

6
provider/yaml/watch.go

@ -33,10 +33,10 @@ func (p *Watch) Read(ctx context.Context, key config.Key) (config.Variable, erro
return config.Variable{}, fmt.Errorf("yaml_file: read error: %w", err)
}
var n yaml.Node
if err = yaml.Unmarshal(in, &n); err != nil {
var yNode yaml.Node
if err = yaml.Unmarshal(in, &yNode); err != nil {
return config.Variable{}, fmt.Errorf("yaml_file: unmarshal error: %w", err)
}
return p.prov.With(&n).Read(ctx, key)
return p.prov.With(&yNode).Read(ctx, key)
}

1
value/decode.go

@ -1,3 +1,4 @@
// nolint: nonamedreturns
package value
import (

2
value/empty.go

@ -8,7 +8,7 @@ type Empty struct {
Err error
}
func (e Empty) Unmarshal(val interface{}) error {
func (e Empty) Unmarshal(_ interface{}) error {
return e.Err
}

16
value/helpers.go

@ -12,7 +12,7 @@ import (
func ParseDuration(raw string) (time.Duration, error) {
d, err := time.ParseDuration(raw)
if err != nil {
return 0, fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return 0, fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return d, nil
@ -21,7 +21,7 @@ func ParseDuration(raw string) (time.Duration, error) {
func ParseInt(s string) (int64, error) {
i, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return 0, fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return 0, fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return i, nil
@ -30,7 +30,7 @@ func ParseInt(s string) (int64, error) {
func ParseUint(s string) (uint64, error) {
i, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return 0, fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return 0, fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return i, nil
@ -39,7 +39,7 @@ func ParseUint(s string) (uint64, error) {
func Atoi(s string) (int, error) {
i, err := strconv.Atoi(s)
if err != nil {
return 0, fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return 0, fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return i, nil
@ -48,7 +48,7 @@ func Atoi(s string) (int, error) {
func ParseTime(s string) (time.Time, error) {
i, err := time.Parse(time.RFC3339, s)
if err != nil {
return time.Time{}, fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return time.Time{}, fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return i, nil
@ -57,7 +57,7 @@ func ParseTime(s string) (time.Time, error) {
func ParseFloat(s string) (float64, error) {
f, err := strconv.ParseFloat(s, 64)
if err != nil {
return 0, fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return 0, fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return f, nil
@ -66,7 +66,7 @@ func ParseFloat(s string) (float64, error) {
func ParseBool(s string) (bool, error) {
b, err := strconv.ParseBool(s)
if err != nil {
return false, fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return false, fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return b, nil
@ -74,7 +74,7 @@ func ParseBool(s string) (bool, error) {
func JUnmarshal(b []byte, v interface{}) error {
if err := json.Unmarshal(b, v); err != nil {
return fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return nil

2
value/value.go

@ -76,7 +76,7 @@ func (s Value) Unmarshal(target interface{}) error {
if v, ok := s.Raw().([]byte); ok {
err := json.Unmarshal(v, target)
if err != nil {
return fmt.Errorf("%w: %s", config.ErrInvalidValue, err)
return fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}
return nil

Loading…
Cancel
Save