update linter

This commit is contained in:
andrey
2025-11-21 11:58:20 +03:00
parent 22dacb741f
commit 72ef747541
25 changed files with 156 additions and 144 deletions

View File

@@ -1,7 +1,13 @@
run:
timeout: 5m
linters-settings:
version: "2"
linters:
default: all
disable:
- noinlineerr
- depguard
- ireturn
# deprecated
- wsl
settings:
dupl:
threshold: 100
funlen:
@@ -12,16 +18,10 @@ linters-settings:
min-occurrences: 2
gocyclo:
min-complexity: 15
golint:
min-confidence: 0
govet:
check-shadowing: true
lll:
line-length: 140
maligned:
suggest-new: true
misspell:
locale: US
locale: US
varnamelen:
min-name-length: 2
ignore-decls:
@@ -31,43 +31,39 @@ linters-settings:
- i int
- b bytes.Buffer
- h Handle
linters:
enable-all: true
disable:
- exhaustivestruct
- maligned
- interfacer
- scopelint
- exhaustruct
- depguard
- nolintlint
#deprecated
- structcheck
- varcheck
- golint
- deadcode
- ifshort
- nosnakecase
- ireturn # implement provider interface
issues:
# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
- path: _test\.go
linters:
- gomnd
- exhaustivestruct
- wrapcheck
- exhaustruct
- varnamelen
- tenv
- funlen
- path: test/*
linters:
- gomnd
- exhaustivestruct
- wrapcheck
- exhaustruct
- varnamelen
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- exhaustivestruct
- exhaustruct
- funlen
- mnd
- tenv
- varnamelen
- wrapcheck
path: _test\.go
- linters:
- exhaustivestruct
- exhaustruct
- mnd
- varnamelen
- wrapcheck
path: test/*
paths:
- third_party$
- builtin$
- examples$
formatters:
default: all
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

View File

@@ -8,7 +8,7 @@ import (
"sync/atomic"
)
func Must(providers ...interface{}) *Client {
func Must(providers ...any) *Client {
client, err := New(providers...)
if err != nil {
panic(err)
@@ -17,7 +17,7 @@ func Must(providers ...interface{}) *Client {
return client
}
func New(providers ...interface{}) (*Client, error) {
func New(providers ...any) (*Client, error) {
client := &Client{
providers: make([]Provider, len(providers)),
}
@@ -31,6 +31,9 @@ func New(providers ...interface{}) (*Client, error) {
factory: func(ctx context.Context) (Provider, error) {
return current(ctx, client)
},
mu: sync.Mutex{},
done: 0,
provider: nil,
}
default:
return nil, fmt.Errorf("provier[%d]: %w %T", idx, ErrUnknowType, prov)
@@ -47,23 +50,6 @@ type provider struct {
factory func(ctx context.Context) (Provider, 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()
var err error
if p.provider, err = p.factory(ctx); err != nil {
return fmt.Errorf("init provider factory:%w", err)
}
}
return nil
}
func (p *provider) Watch(ctx context.Context, callback WatchCallback, path ...string) error {
if err := p.init(ctx); err != nil {
return fmt.Errorf("init read:%w", err)
@@ -94,6 +80,23 @@ func (p *provider) Value(ctx context.Context, path ...string) (Value, error) {
return variable, nil
}
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()
var err error
if p.provider, err = p.factory(ctx); err != nil {
return fmt.Errorf("init provider factory:%w", err)
}
}
return nil
}
type Client struct {
providers []Provider
}
@@ -111,7 +114,7 @@ func (c *Client) Value(ctx context.Context, path ...string) (Value, error) {
for _, provider := range c.providers {
value, err = provider.Value(ctx, path...)
if err == nil || !(errors.Is(err, ErrValueNotFound) || errors.Is(err, ErrInitFactory)) {
if err == nil || (!errors.Is(err, ErrValueNotFound) && !errors.Is(err, ErrInitFactory)) {
break
}
}

View File

@@ -79,7 +79,7 @@ func ExampleClient_Watch() {
wg := sync.WaitGroup{}
wg.Add(1)
err = watcher.Watch(ctx, func(ctx context.Context, oldVar, newVar config.Value) error {
err = watcher.Watch(ctx, func(_ context.Context, oldVar, newVar config.Value) error {
fmt.Println("update example_enable old: ", oldVar.Bool(), " new:", newVar.Bool())
wg.Done()
@@ -93,7 +93,7 @@ func ExampleClient_Watch() {
_ = os.Setenv("FDEVS_CONFIG_EXAMPLE_ENABLE", "false")
err = watcher.Watch(ctx, func(ctx context.Context, oldVar, newVar config.Value) error {
err = watcher.Watch(ctx, func(_ context.Context, oldVar, newVar config.Value) error {
fmt.Println("update example_db_dsn old: ", oldVar.String(), " new:", newVar.String())
wg.Done()

View File

@@ -141,7 +141,7 @@ func (v View) Parse(valName string, value string, keys []string) string {
return data
}
//nolint:gochecknoglobals,unparam
//nolint:gochecknoglobals
var parses = map[string]func(data ParseData) (string, error){
typesIntreface[0].Name(): func(data ParseData) (string, error) {
var b bytes.Buffer

2
go.mod
View File

@@ -1,3 +1,3 @@
module gitoa.ru/go-4devs/config
go 1.21
go 1.23

View File

@@ -43,8 +43,44 @@ type Provider struct {
name string
}
// nolint: cyclop
// return name, value, error.
func (p *Provider) Name() string {
return p.name
}
func (p *Provider) Value(_ context.Context, path ...string) (config.Value, error) {
err := p.parse()
if err != nil {
return nil, err
}
name := p.key(path...)
if val, ok := p.args[name]; ok {
switch {
case len(val) == 1:
return value.JString(val[0]), nil
default:
data, jerr := json.Marshal(val)
if jerr != nil {
return nil, fmt.Errorf("failed load data:%w", jerr)
}
return value.Decode(func(v any) error {
err := json.Unmarshal(data, v)
if err != nil {
return fmt.Errorf("unmarshal:%w", err)
}
return nil
}), nil
}
}
return nil, fmt.Errorf("%s:%w", p.Name(), config.ErrValueNotFound)
}
// parseOne return name, value, error.
//
//nolint:cyclop
func (p *Provider) parseOne(arg string) (string, string, error) {
if arg[0] != '-' {
return "", "", nil
@@ -101,36 +137,3 @@ func (p *Provider) parse() error {
return nil
}
func (p *Provider) Name() string {
return p.name
}
func (p *Provider) Value(_ context.Context, path ...string) (config.Value, error) {
if err := p.parse(); err != nil {
return nil, err
}
name := p.key(path...)
if val, ok := p.args[name]; ok {
switch {
case len(val) == 1:
return value.JString(val[0]), nil
default:
data, jerr := json.Marshal(val)
if jerr != nil {
return nil, fmt.Errorf("failed load data:%w", jerr)
}
return value.Decode(func(v interface{}) error {
if err := json.Unmarshal(data, v); err != nil {
return fmt.Errorf("unmarshal:%w", err)
}
return nil
}), nil
}
}
return nil, fmt.Errorf("%s:%w", p.Name(), config.ErrValueNotFound)
}

View File

@@ -65,5 +65,5 @@ func (d *Duration) UnmarshalJSON(in []byte) error {
}
func (d *Duration) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("%q", d)), nil
return fmt.Appendf(nil, "%q", d), nil
}

View File

@@ -26,6 +26,7 @@ func New(namespace, appName string, opts ...Option) *Provider {
return strings.ToUpper(strings.Join(path, "_"))
},
prefix: strings.ToUpper(namespace + "_" + appName + "_"),
name: "",
}
for _, opt := range opts {

View File

@@ -1,7 +1,6 @@
package env_test
import (
"os"
"testing"
"gitoa.ru/go-4devs/config/provider/env"
@@ -9,10 +8,8 @@ import (
)
func TestProvider(t *testing.T) {
t.Parallel()
os.Setenv("FDEVS_CONFIG_DSN", test.DSN)
os.Setenv("FDEVS_CONFIG_PORT", "8080")
t.Setenv("FDEVS_CONFIG_DSN", test.DSN)
t.Setenv("FDEVS_CONFIG_PORT", "8080")
provider := env.New("fdevs", "config")

View File

@@ -39,18 +39,20 @@ type Option func(*Provider)
type Provider struct {
config.Provider
duration time.Duration
logger func(context.Context, string, ...any)
}
func (p *Provider) Watch(ctx context.Context, callback config.WatchCallback, key ...string) error {
old, err := p.Provider.Value(ctx, key...)
old, err := p.Value(ctx, key...)
if err != nil {
return fmt.Errorf("failed watch variable: %w", err)
}
go func(oldVar config.Value) {
ticker := time.NewTicker(p.duration)
defer func() {
ticker.Stop()
}()
@@ -58,7 +60,7 @@ func (p *Provider) Watch(ctx context.Context, callback config.WatchCallback, key
for {
select {
case <-ticker.C:
newVar, err := p.Provider.Value(ctx, key...)
newVar, err := p.Value(ctx, key...)
if err != nil {
p.logger(ctx, "get value%v:%v", key, err.Error())
} else if !newVar.IsEquals(oldVar) {
@@ -66,8 +68,10 @@ func (p *Provider) Watch(ctx context.Context, callback config.WatchCallback, key
if errors.Is(err, config.ErrStopWatch) {
return
}
p.logger(ctx, "callback %v:%v", key, err)
}
oldVar = newVar
}
case <-ctx.Done():

View File

@@ -34,6 +34,7 @@ func TestWatcher(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
defer func() {
cancel()
}()
@@ -48,9 +49,10 @@ func TestWatcher(t *testing.T) {
err := w.Watch(
ctx,
func(ctx context.Context, oldVar, newVar config.Value) error {
func(_ context.Context, _, _ config.Value) error {
atomic.AddInt32(&cnt, 1)
wg.Done()
if atomic.LoadInt32(&cnt) == 2 {
return config.ErrStopWatch
}

View File

@@ -5,7 +5,7 @@ import (
"testing"
)
func Equal(t *testing.T, expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
func Equal(t *testing.T, expected any, actual any, msgAndArgs ...any) bool {
t.Helper()
if reflect.DeepEqual(expected, actual) {
@@ -17,7 +17,7 @@ func Equal(t *testing.T, expected interface{}, actual interface{}, msgAndArgs ..
return false
}
func Equalf(t *testing.T, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
func Equalf(t *testing.T, expected any, actual any, msg string, args ...any) bool {
t.Helper()
if reflect.DeepEqual(expected, actual) {

View File

@@ -2,7 +2,7 @@ package assert
import "testing"
func Nil(t *testing.T, data any, msgAndArgs ...interface{}) bool {
func Nil(t *testing.T, data any, msgAndArgs ...any) bool {
t.Helper()
if data != nil {

View File

@@ -49,7 +49,7 @@ func NewReadConfig(key ...string) Read {
return NewReadUnmarshal(ex, &Config{}, key...)
}
func NewReadUnmarshal(expected, target interface{}, key ...string) Read {
func NewReadUnmarshal(expected, target any, key ...string) Read {
return Read{
Key: key,
Assert: func(t *testing.T, v config.Value) {
@@ -66,17 +66,21 @@ func Time(value string) time.Time {
return t
}
// nolint: cyclop
func NewRead(expected interface{}, key ...string) Read {
// NewRead test data.
//
//nolint:cyclop
func NewRead(expected any, key ...string) Read {
return Read{
Key: key,
Assert: func(t *testing.T, v config.Value) {
t.Helper()
var (
val interface{}
val any
err error
short interface{}
short any
)
switch expected.(type) {
case bool:
val, err = v.ParseBool()

View File

@@ -6,7 +6,7 @@ import (
"gitoa.ru/go-4devs/config/test/assert"
)
func Equal(t *testing.T, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
func Equal(t *testing.T, expected any, actual any, msgAndArgs ...any) {
t.Helper()
if assert.Equal(t, expected, actual, msgAndArgs...) {
@@ -16,7 +16,7 @@ func Equal(t *testing.T, expected interface{}, actual interface{}, msgAndArgs ..
t.FailNow()
}
func Equalf(t *testing.T, expected interface{}, actual interface{}, msg string, args ...interface{}) {
func Equalf(t *testing.T, expected any, actual any, msg string, args ...any) {
t.Helper()
if assert.Equalf(t, expected, actual, msg, args...) {

View File

@@ -4,7 +4,7 @@ import (
"testing"
)
func NoError(t *testing.T, err error, msgAndArgs ...interface{}) {
func NoError(t *testing.T, err error, msgAndArgs ...any) {
t.Helper()
if err != nil {
@@ -13,7 +13,7 @@ func NoError(t *testing.T, err error, msgAndArgs ...interface{}) {
}
}
func NoErrorf(t *testing.T, err error, msg string, args ...interface{}) {
func NoErrorf(t *testing.T, err error, msg string, args ...any) {
t.Helper()
if err != nil {

View File

@@ -2,7 +2,7 @@ package require
import "testing"
func Fail(t *testing.T, msg string, args ...interface{}) {
func Fail(t *testing.T, msg string, args ...any) {
t.Helper()
t.Errorf(msg, args...)
t.FailNow()

View File

@@ -4,7 +4,7 @@ import (
"testing"
)
func Truef(t *testing.T, value bool, msg string, args ...interface{}) {
func Truef(t *testing.T, value bool, msg string, args ...any) {
t.Helper()
if !value {

View File

@@ -12,7 +12,7 @@ type Value interface {
}
type UnmarshalValue interface {
Unmarshal(val interface{}) error
Unmarshal(val any) error
}
type ReadValue interface {

View File

@@ -1,4 +1,6 @@
// nolint: nonamedreturns
// Package value decode value.
//
//nolint:nonamedreturns
package value
import (
@@ -9,9 +11,9 @@ import (
var _ config.Value = (*Decode)(nil)
type Decode func(v interface{}) error
type Decode func(v any) error
func (s Decode) Unmarshal(v interface{}) error {
func (s Decode) Unmarshal(v any) error {
return s(v)
}

View File

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

View File

@@ -72,7 +72,7 @@ func ParseBool(s string) (bool, error) {
return b, nil
}
func JUnmarshal(b []byte, v interface{}) error {
func JUnmarshal(b []byte, v any) error {
if err := json.Unmarshal(b, v); err != nil {
return fmt.Errorf("%w: %w", config.ErrInvalidValue, err)
}

View File

@@ -10,7 +10,7 @@ var _ config.Value = (*JBytes)(nil)
type JBytes []byte
func (s JBytes) Unmarshal(v interface{}) error {
func (s JBytes) Unmarshal(v any) error {
return JUnmarshal(s.Bytes(), v)
}

View File

@@ -10,7 +10,7 @@ var _ config.Value = (*JString)(nil)
type JString string
func (s JString) Unmarshal(v interface{}) error {
func (s JString) Unmarshal(v any) error {
return JUnmarshal(s.Bytes(), v)
}

View File

@@ -11,7 +11,7 @@ import (
var _ config.Value = (*Value)(nil)
type Value struct {
Val interface{}
Val any
}
func (s Value) Int() int {
@@ -62,7 +62,7 @@ func (s Value) Duration() time.Duration {
return v
}
func (s Value) Raw() interface{} {
func (s Value) Raw() any {
return s.Val
}
@@ -72,7 +72,7 @@ func (s Value) Time() time.Time {
return v
}
func (s Value) Unmarshal(target interface{}) error {
func (s Value) Unmarshal(target any) error {
if v, ok := s.Raw().([]byte); ok {
err := json.Unmarshal(v, target)
if err != nil {