From 8faed36cc040a7e8295a15559a3bafce983d4cee Mon Sep 17 00:00:00 2001 From: xgfone Date: Sat, 1 Apr 2023 19:23:55 +0800 Subject: [PATCH] update the dependencies and require go1.18+ --- .github/workflows/go.yml | 12 ++--- .gitignore | 14 +++++- README.md | 2 +- atomic_value_1.17.go | 24 ---------- atomic_value_1.17_compat.go | 27 ----------- config.go | 8 +--- go.mod | 11 +++-- go.sum | 18 +++---- opt_proxy_test.go | 5 ++ utils.go | 93 ++++++++++++++++++++++++++++--------- 10 files changed, 113 insertions(+), 101 deletions(-) delete mode 100644 atomic_value_1.17.go delete mode 100644 atomic_value_1.17_compat.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 951f5ff..0dee054 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -9,17 +9,13 @@ jobs: strategy: matrix: go: - - '1.13' - - '1.14' - - '1.15' - - '1.16' - - '1.17' - '1.18' - '1.19' + - '1.20' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: ${{ matrix.go }} - - run: go test -race -v + - run: go test -race -cover diff --git a/.gitignore b/.gitignore index 45d8969..8bcebb9 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,6 @@ _cgo_export.* _testmain.go -.* *.exe *.test *.prof @@ -34,5 +33,16 @@ test_* # log *.log -# Unix hidden files +vendor/ + +# VS Code +.vscode/ +debug +debug_test + +# Mac +.DS_Store + +# hidden files .* +_* diff --git a/README.md b/README.md index 5444786..2e4b2c8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Go Config [![Build Status](https://github.com/xgfone/gconf/actions/workflows/go.yml/badge.svg)](https://github.com/xgfone/gconf/actions/workflows/go.yml) [![GoDoc](https://pkg.go.dev/badge/github.com/xgfone/gconf)](https://pkg.go.dev/github.com/xgfone/gconf/v6) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square)](https://raw.githubusercontent.com/xgfone/gconf/master/LICENSE) -An extensible and powerful go configuration manager supporting `Go1.13+`, which is inspired by [oslo.config](https://github.com/openstack/oslo.config), [viper](https://github.com/spf13/viper) and [github.com/micro/go-micro/config](https://github.com/micro/go-micro/tree/master/config). +An extensible and powerful go configuration manager supporting `Go1.18+`, which is inspired by [oslo.config](https://github.com/openstack/oslo.config), [viper](https://github.com/spf13/viper) and [github.com/micro/go-micro/config](https://github.com/micro/go-micro/tree/master/config). ## Install diff --git a/atomic_value_1.17.go b/atomic_value_1.17.go deleted file mode 100644 index c6af1ab..0000000 --- a/atomic_value_1.17.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2021 xgfone -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build go1.17 -// +build go1.17 - -package gconf - -import "sync/atomic" - -func (v *atomicValue) Swap(new interface{}) (old interface{}) { - return (*atomic.Value)(v).Swap(new) -} diff --git a/atomic_value_1.17_compat.go b/atomic_value_1.17_compat.go deleted file mode 100644 index 49008ce..0000000 --- a/atomic_value_1.17_compat.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2021 xgfone -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build !go1.17 -// +build !go1.17 - -package gconf - -import "sync/atomic" - -func (v *atomicValue) Swap(new interface{}) (old interface{}) { - av := (*atomic.Value)(v) - old = av.Load() - av.Store(new) - return -} diff --git a/config.go b/config.go index 1b5612d..3ac13bd 100644 --- a/config.go +++ b/config.go @@ -1,4 +1,4 @@ -// Copyright 2021~2022 xgfone +// Copyright 2021~2023 xgfone // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -34,12 +34,8 @@ var VersionOpt = StrOpt("version", "Print the version and exit.").S("v").D("1.0. // Conf is the default global Config. var Conf = New() -type atomicValue atomic.Value - -func (v *atomicValue) Load() interface{} { return (*atomic.Value)(v).Load() } - type option struct { - value atomicValue + value atomic.Value opt Opt } diff --git a/go.mod b/go.mod index bdd6b03..87743b5 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,12 @@ module github.com/xgfone/gconf/v6 require ( - github.com/fsnotify/fsnotify v1.5.4 - github.com/xgfone/cast v0.5.1 - gopkg.in/yaml.v2 v2.3.0 + github.com/fsnotify/fsnotify v1.6.0 + github.com/xgfone/go-cast v0.7.0 + github.com/xgfone/go-defaults v0.2.0 + gopkg.in/yaml.v2 v2.4.0 ) -go 1.13 +require golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect + +go 1.18 diff --git a/go.sum b/go.sum index 88c594c..6da32a1 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,12 @@ -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/xgfone/cast v0.5.1 h1:m9d/iTkTp0f8XEG162mPQNLlDoJWSKrIV7fbkEgIPMg= -github.com/xgfone/cast v0.5.1/go.mod h1:T+gPbsD/fD72zz9wy/XaLTv236sPHaf6TcT7uvIhV/k= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/xgfone/go-cast v0.7.0 h1:pl7IF94w+OkwpWzKQ8wnpXD+qHFiQFJqMhmvk13PxjI= +github.com/xgfone/go-cast v0.7.0/go.mod h1:FRbU3FALpDh1PW5SjIo6XeM5VPcEBZaOBMtFUfxfkiU= +github.com/xgfone/go-defaults v0.2.0 h1:1/k2GdF3X2HzBWtOu/jaLgK6E+7gd4Nq4q6rEzBl2mU= +github.com/xgfone/go-defaults v0.2.0/go.mod h1:zwcnD8escc6E5QrCNKRLQddb4/hcUnUOM20kUeki18Y= +golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/opt_proxy_test.go b/opt_proxy_test.go index f6bda1f..53b50ac 100644 --- a/opt_proxy_test.go +++ b/opt_proxy_test.go @@ -20,9 +20,12 @@ import ( "reflect" "testing" "time" + + "github.com/xgfone/go-defaults" ) func TestOptProxy(t *testing.T) { + defaults.TimeLocation.Set(time.Local) Conf.reset() boolopt := NewBool("bool", false, "bool") @@ -159,6 +162,8 @@ func TestOptProxy(t *testing.T) { } func TestOptGroupProxy(t *testing.T) { + defaults.TimeLocation.Set(time.Local) + config := New() group := config.Group("group1.group2") boolopt := group.NewBool("bool", false, "bool") diff --git a/utils.go b/utils.go index 713ec47..a2f185c 100644 --- a/utils.go +++ b/utils.go @@ -1,4 +1,4 @@ -// Copyright 2019 xgfone +// Copyright 2019~2023 xgfone // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -18,28 +18,29 @@ import ( "crypto/md5" "crypto/sha256" "fmt" + "reflect" "strings" "time" - "github.com/xgfone/cast" + "github.com/xgfone/go-cast" ) // Some type converters, all of which have a default implementation, // but you can reset them to yourself implementations. var ( ToBool = cast.ToBool // func(interface{}) (bool, error) - ToInt = cast.ToInt // func(interface{}) (int, error) - ToInt16 = cast.ToInt16 // func(interface{}) (int16, error) - ToInt32 = cast.ToInt32 // func(interface{}) (int32, error) ToInt64 = cast.ToInt64 // func(interface{}) (int64, error) - ToUint = cast.ToUint // func(interface{}) (uint, error) - ToUint16 = cast.ToUint16 // func(interface{}) (uint16, error) - ToUint32 = cast.ToUint32 // func(interface{}) (uint32, error) ToUint64 = cast.ToUint64 // func(interface{}) (uint64, error) ToFloat64 = cast.ToFloat64 // func(interface{}) (float64, error) ToString = cast.ToString // func(interface{}) (string, error) ToDuration = cast.ToDuration // func(interface{}) (time.Duration, error) - ToTime = toTime // func(interface{}) (time.Time, error) + ToTime = cast.ToTime // func(interface{}) (time.Time, error) + ToInt = toInt // func(interface{}) (int, error) + ToInt16 = toInt16 // func(interface{}) (int16, error) + ToInt32 = toInt32 // func(interface{}) (int32, error) + ToUint = toUint // func(interface{}) (uint, error) + ToUint16 = toUint16 // func(interface{}) (uint16, error) + ToUint32 = toUint32 // func(interface{}) (uint32, error) // For string type, it will be split by using cast.ToStringSlice. ToIntSlice = toIntSlice // func(interface{}) ([]int, error) @@ -49,14 +50,31 @@ var ( ToDurationSlice = toDurationSlice // func(interface{}) ([]time.Duration, error) ) -var toStringMap = cast.ToStringMap - -func init() { - cast.StringSeparator = " ," +func toInt(v interface{}) (int, error) { + return to(v, cast.ToInt64, func(v int64) int { return int(v) }) +} +func toInt16(v interface{}) (int16, error) { + return to(v, cast.ToInt64, func(v int64) int16 { return int16(v) }) +} +func toInt32(v interface{}) (int32, error) { + return to(v, cast.ToInt64, func(v int64) int32 { return int32(v) }) +} +func toUint(v interface{}) (uint, error) { + return to(v, cast.ToInt64, func(v int64) uint { return uint(v) }) +} +func toUint16(v interface{}) (uint16, error) { + return to(v, cast.ToInt64, func(v int64) uint16 { return uint16(v) }) +} +func toUint32(v interface{}) (uint32, error) { + return to(v, cast.ToInt64, func(v int64) uint32 { return uint32(v) }) } -func toTime(v interface{}) (time.Time, error) { - return cast.ToTime(v) +func to[T1, T2 any](i interface{}, f func(interface{}) (T1, error), m func(T1) T2) (v T2, err error) { + _v, err := f(i) + if err == nil { + v = m(_v) + } + return } func bytesToMd5(data []byte) string { @@ -71,6 +89,15 @@ func bytesToSha256(data []byte) string { return fmt.Sprintf("%x", h.Sum(nil)) } +func isStringSeparator(r rune) bool { + switch r { + case ' ', ',', '\t': + return true + default: + return false + } +} + func getStringSlice(value interface{}) []string { var s string switch v := value.(type) { @@ -86,7 +113,7 @@ func getStringSlice(value interface{}) []string { return nil } - vs, _ := cast.ToStringSlice(s) + vs := strings.FieldsFunc(s, isStringSeparator) ss := make([]string, 0, len(vs)) for _, s := range vs { if s = strings.TrimSpace(s); s != "" { @@ -96,6 +123,30 @@ func getStringSlice(value interface{}) []string { return ss } +func toSlice[E any](value interface{}, to func(interface{}) (E, error)) ([]E, error) { + switch v := value.(type) { + case nil: + return []E{}, nil + case []E: + return v, nil + } + + switch reflect.TypeOf(value).Kind() { + case reflect.Slice, reflect.Array: + var err error + vf := reflect.ValueOf(value) + vs := make([]E, vf.Len()) + for i, _len := 0, vf.Len(); i < _len; i++ { + if vs[i], err = to(vf.Index(i).Interface()); err != nil { + return []E{}, fmt.Errorf("unable to cast %#v of type %T to []int", value, value) + } + } + return vs, nil + default: + return []E{}, fmt.Errorf("unable to cast %#v of type %T to []int", value, value) + } +} + func toIntSlice(value interface{}) ([]int, error) { if ss := getStringSlice(value); ss != nil { var err error @@ -107,7 +158,7 @@ func toIntSlice(value interface{}) ([]int, error) { } return vs, nil } - return cast.ToIntSlice(value) + return toSlice(value, ToInt) } func toUintSlice(value interface{}) (v []uint, err error) { @@ -121,7 +172,7 @@ func toUintSlice(value interface{}) (v []uint, err error) { } return vs, nil } - return cast.ToUintSlice(value) + return toSlice(value, ToUint) } func toFloat64Slice(value interface{}) ([]float64, error) { @@ -135,14 +186,14 @@ func toFloat64Slice(value interface{}) ([]float64, error) { } return vs, nil } - return cast.ToFloat64Slice(value) + return toSlice(value, ToFloat64) } func toStringSlice(value interface{}) ([]string, error) { if ss := getStringSlice(value); ss != nil { return ss, nil } - return cast.ToStringSlice(value) + return toSlice(value, ToString) } func toDurationSlice(value interface{}) ([]time.Duration, error) { @@ -156,7 +207,7 @@ func toDurationSlice(value interface{}) ([]time.Duration, error) { } return vs, nil } - return cast.ToDurationSlice(value) + return toSlice(value, ToDuration) } func inString(s string, ss []string) bool {