From 0df009eae08f0f02902b46bd0359937ecdd3fab3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 08:57:34 +0000 Subject: [PATCH] Bump github.com/gookit/config/v2 from 2.2.3 to 2.2.4 Bumps [github.com/gookit/config/v2](https://github.com/gookit/config) from 2.2.3 to 2.2.4. - [Release notes](https://github.com/gookit/config/releases) - [Commits](https://github.com/gookit/config/compare/v2.2.3...v2.2.4) --- updated-dependencies: - dependency-name: github.com/gookit/config/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 8 +- go.sum | 16 +- vendor/github.com/goccy/go-yaml/CHANGELOG.md | 23 + vendor/github.com/goccy/go-yaml/ast/ast.go | 4 +- vendor/github.com/goccy/go-yaml/encode.go | 4 + .../goccy/go-yaml/parser/context.go | 7 - .../github.com/goccy/go-yaml/parser/parser.go | 41 +- vendor/github.com/goccy/go-yaml/path.go | 26 +- .../goccy/go-yaml/scanner/scanner.go | 5 + .../github.com/goccy/go-yaml/token/token.go | 4 +- vendor/github.com/goccy/go-yaml/yaml.go | 62 +- vendor/github.com/gookit/color/color_16.go | 49 +- vendor/github.com/gookit/color/color_256.go | 20 +- vendor/github.com/gookit/color/color_rgb.go | 15 +- vendor/github.com/gookit/color/convert.go | 24 +- vendor/github.com/gookit/color/style.go | 6 +- vendor/github.com/gookit/config/v2/export.go | 16 +- vendor/github.com/gookit/config/v2/read.go | 15 + vendor/github.com/gookit/config/v2/util.go | 9 +- vendor/github.com/gookit/goutil/.gitignore | 1 + vendor/github.com/gookit/goutil/README.md | 1981 +++++++++-------- .../github.com/gookit/goutil/README.zh-CN.md | 1969 ++++++++-------- .../gookit/goutil/arrutil/arrutil.go | 114 - .../github.com/gookit/goutil/arrutil/check.go | 24 +- .../gookit/goutil/arrutil/collection.go | 464 ++-- .../goutil/arrutil/collection_gte118.go | 22 - .../gookit/goutil/arrutil/convert.go | 92 +- .../github.com/gookit/goutil/arrutil/enum.go | 64 - .../gookit/goutil/arrutil/format.go | 14 +- .../github.com/gookit/goutil/arrutil/list.go | 216 ++ .../gookit/goutil/arrutil/process.go | 102 + .../gookit/goutil/arrutil/strings.go | 137 ++ .../goutil/basefn/{basefunc.go => basefn.go} | 41 +- .../gookit/goutil/byteutil/buffer.go | 7 + .../gookit/goutil/byteutil/byteutil.go | 71 +- .../gookit/goutil/byteutil/bytex.go | 19 - .../github.com/gookit/goutil/byteutil/conv.go | 109 + .../gookit/goutil/byteutil/encoder.go | 12 +- .../github.com/gookit/goutil/byteutil/pool.go | 11 +- vendor/github.com/gookit/goutil/check.go | 9 +- .../gookit/goutil/cliutil/cmdline/builder.go | 4 +- .../gookit/goutil/cliutil/cmdline/parser.go | 4 +- .../github.com/gookit/goutil/comdef/comdef.go | 44 +- .../gookit/goutil/comdef/interface.go | 70 + .../github.com/gookit/goutil/comdef/types.go | 29 +- vendor/github.com/gookit/goutil/conv.go | 162 +- .../gookit/goutil/encodes/encodes.go | 66 + .../gookit/goutil/envutil/README.md | 2 +- .../gookit/goutil/envutil/envutil.go | 31 +- .../github.com/gookit/goutil/envutil/get.go | 13 +- .../github.com/gookit/goutil/errorx/assert.go | 10 +- .../github.com/gookit/goutil/errorx/errors.go | 15 +- .../github.com/gookit/goutil/errorx/errorx.go | 7 +- .../github.com/gookit/goutil/errorx/stack.go | 4 +- .../github.com/gookit/goutil/errorx/util.go | 15 + .../github.com/gookit/goutil/fsutil/check.go | 13 + .../github.com/gookit/goutil/fsutil/define.go | 109 + .../github.com/gookit/goutil/fsutil/find.go | 60 +- .../github.com/gookit/goutil/fsutil/fsutil.go | 73 - .../github.com/gookit/goutil/fsutil/info.go | 3 + .../gookit/goutil/fsutil/info_nonwin.go | 1 + .../github.com/gookit/goutil/fsutil/mime.go | 40 + .../gookit/goutil/fsutil/operate.go | 79 +- .../github.com/gookit/goutil/fsutil/opread.go | 29 +- .../gookit/goutil/fsutil/opwrite.go | 81 +- vendor/github.com/gookit/goutil/func.go | 57 +- .../github.com/gookit/goutil/goinfo/README.md | 34 + .../goutil/{stdutil => goinfo}/gofunc.go | 48 +- .../github.com/gookit/goutil/goinfo/goinfo.go | 78 + .../goutil/{stdutil => goinfo}/stack.go | 15 +- vendor/github.com/gookit/goutil/goutil.go | 22 +- vendor/github.com/gookit/goutil/group.go | 33 +- .../gookit/goutil/internal/checkfn/check.go | 78 + .../gookit/goutil/internal/comfunc/README.md | 3 + .../gookit/goutil/internal/comfunc/comfunc.go | 90 +- .../gookit/goutil/internal/comfunc/convert.go | 23 + .../gookit/goutil/internal/varexpr/varexpr.go | 145 ++ .../gookit/goutil/jsonutil/encoding.go | 64 + .../gookit/goutil/jsonutil/jsonbuild.go | 21 + .../gookit/goutil/jsonutil/jsonutil.go | 85 +- .../github.com/gookit/goutil/maputil/alias.go | 6 +- .../github.com/gookit/goutil/maputil/data.go | 5 +- .../gookit/goutil/maputil/format.go | 8 +- .../github.com/gookit/goutil/maputil/get.go | 89 +- .../github.com/gookit/goutil/maputil/smap.go | 12 + .../gookit/goutil/mathutil/README.md | 82 +- .../gookit/goutil/mathutil/check.go | 82 +- .../gookit/goutil/mathutil/compare.go | 76 + .../gookit/goutil/mathutil/convert.go | 333 ++- .../{basefn/extfunc.go => mathutil/format.go} | 16 +- .../gookit/goutil/mathutil/mathutil.go | 112 +- .../gookit/goutil/mathutil/number.go | 37 - .../gookit/goutil/mathutil/random.go | 8 +- .../gookit/goutil/reflects/check.go | 38 +- .../github.com/gookit/goutil/reflects/conv.go | 106 +- .../github.com/gookit/goutil/reflects/func.go | 317 +++ .../github.com/gookit/goutil/reflects/map.go | 83 + .../gookit/goutil/reflects/reflects.go | 15 + .../gookit/goutil/reflects/slice.go | 61 + .../github.com/gookit/goutil/reflects/type.go | 37 +- .../github.com/gookit/goutil/reflects/util.go | 149 +- .../gookit/goutil/reflects/value.go | 5 +- .../github.com/gookit/goutil/stdio/iface.go | 35 + .../github.com/gookit/goutil/stdio/stdio.go | 12 +- .../github.com/gookit/goutil/stdio/writer.go | 5 + .../gookit/goutil/stdutil/README.md | 28 - .../github.com/gookit/goutil/stdutil/check.go | 135 -- .../github.com/gookit/goutil/stdutil/conv.go | 50 - .../gookit/goutil/stdutil/stdutil.go | 34 - .../github.com/gookit/goutil/stdutil/value.go | 8 - .../github.com/gookit/goutil/structs/alias.go | 2 +- .../github.com/gookit/goutil/structs/data.go | 29 +- .../github.com/gookit/goutil/structs/init.go | 11 +- .../github.com/gookit/goutil/structs/smap.go | 4 +- .../github.com/gookit/goutil/structs/tags.go | 1 - .../gookit/goutil/structs/wrapper.go | 40 +- .../github.com/gookit/goutil/strutil/check.go | 9 + .../gookit/goutil/strutil/convbase.go | 80 + .../gookit/goutil/strutil/convert.go | 405 ++-- .../gookit/goutil/strutil/encode.go | 73 +- .../github.com/gookit/goutil/strutil/ext.go | 7 + .../github.com/gookit/goutil/strutil/gensn.go | 124 ++ .../goutil/strutil/{crypto.go => hash.go} | 19 +- vendor/github.com/gookit/goutil/strutil/id.go | 69 - .../gookit/goutil/strutil/padding.go | 48 +- .../github.com/gookit/goutil/strutil/parse.go | 6 +- .../gookit/goutil/strutil/random.go | 93 +- .../github.com/gookit/goutil/strutil/runes.go | 6 +- .../github.com/gookit/goutil/strutil/split.go | 32 + .../gookit/goutil/strutil/strutil.go | 97 +- .../gookit/goutil/strutil/textutil/litetpl.go | 277 +++ .../gookit/goutil/strutil/textutil/texttpl.go | 90 + .../goutil/strutil/textutil/var_replacer.go | 53 +- vendor/github.com/gookit/goutil/syncs/chan.go | 35 + .../github.com/gookit/goutil/syncs/group.go | 46 + .../{stdutil/chan.go => syncs/signal.go} | 24 +- .../github.com/gookit/goutil/syncs/syncs.go | 2 + .../github.com/gookit/goutil/sysutil/sysgo.go | 57 +- .../gookit/goutil/sysutil/user_nonwin.go | 13 +- .../gookit/goutil/sysutil/user_windows.go | 9 +- vendor/modules.txt | 20 +- 141 files changed, 7314 insertions(+), 4044 deletions(-) delete mode 100644 vendor/github.com/gookit/goutil/arrutil/collection_gte118.go delete mode 100644 vendor/github.com/gookit/goutil/arrutil/enum.go create mode 100644 vendor/github.com/gookit/goutil/arrutil/list.go create mode 100644 vendor/github.com/gookit/goutil/arrutil/process.go create mode 100644 vendor/github.com/gookit/goutil/arrutil/strings.go rename vendor/github.com/gookit/goutil/basefn/{basefunc.go => basefn.go} (68%) delete mode 100644 vendor/github.com/gookit/goutil/byteutil/bytex.go create mode 100644 vendor/github.com/gookit/goutil/byteutil/conv.go create mode 100644 vendor/github.com/gookit/goutil/comdef/interface.go create mode 100644 vendor/github.com/gookit/goutil/encodes/encodes.go create mode 100644 vendor/github.com/gookit/goutil/fsutil/define.go create mode 100644 vendor/github.com/gookit/goutil/fsutil/mime.go create mode 100644 vendor/github.com/gookit/goutil/goinfo/README.md rename vendor/github.com/gookit/goutil/{stdutil => goinfo}/gofunc.go (60%) create mode 100644 vendor/github.com/gookit/goutil/goinfo/goinfo.go rename vendor/github.com/gookit/goutil/{stdutil => goinfo}/stack.go (90%) create mode 100644 vendor/github.com/gookit/goutil/internal/checkfn/check.go create mode 100644 vendor/github.com/gookit/goutil/internal/comfunc/README.md create mode 100644 vendor/github.com/gookit/goutil/internal/varexpr/varexpr.go create mode 100644 vendor/github.com/gookit/goutil/jsonutil/encoding.go create mode 100644 vendor/github.com/gookit/goutil/jsonutil/jsonbuild.go create mode 100644 vendor/github.com/gookit/goutil/mathutil/compare.go rename vendor/github.com/gookit/goutil/{basefn/extfunc.go => mathutil/format.go} (86%) delete mode 100644 vendor/github.com/gookit/goutil/mathutil/number.go create mode 100644 vendor/github.com/gookit/goutil/reflects/func.go create mode 100644 vendor/github.com/gookit/goutil/reflects/map.go create mode 100644 vendor/github.com/gookit/goutil/reflects/slice.go create mode 100644 vendor/github.com/gookit/goutil/stdio/iface.go delete mode 100644 vendor/github.com/gookit/goutil/stdutil/README.md delete mode 100644 vendor/github.com/gookit/goutil/stdutil/check.go delete mode 100644 vendor/github.com/gookit/goutil/stdutil/conv.go delete mode 100644 vendor/github.com/gookit/goutil/stdutil/stdutil.go delete mode 100644 vendor/github.com/gookit/goutil/stdutil/value.go create mode 100644 vendor/github.com/gookit/goutil/strutil/convbase.go create mode 100644 vendor/github.com/gookit/goutil/strutil/gensn.go rename vendor/github.com/gookit/goutil/strutil/{crypto.go => hash.go} (78%) delete mode 100644 vendor/github.com/gookit/goutil/strutil/id.go create mode 100644 vendor/github.com/gookit/goutil/strutil/textutil/litetpl.go create mode 100644 vendor/github.com/gookit/goutil/strutil/textutil/texttpl.go create mode 100644 vendor/github.com/gookit/goutil/syncs/chan.go create mode 100644 vendor/github.com/gookit/goutil/syncs/group.go rename vendor/github.com/gookit/goutil/{stdutil/chan.go => syncs/signal.go} (65%) create mode 100644 vendor/github.com/gookit/goutil/syncs/syncs.go diff --git a/go.mod b/go.mod index 32123c811..ca05b2c56 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/google/go-tika v0.3.0 github.com/google/uuid v1.4.0 - github.com/gookit/config/v2 v2.2.3 + github.com/gookit/config/v2 v2.2.4 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 github.com/jellydator/ttlcache/v2 v2.11.1 @@ -204,7 +204,7 @@ require ( github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/ws v1.0.4 // indirect - github.com/goccy/go-yaml v1.11.0 // indirect + github.com/goccy/go-yaml v1.11.2 // indirect github.com/godbus/dbus/v5 v5.0.6 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -217,8 +217,8 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/renameio/v2 v2.0.0 // indirect - github.com/gookit/color v1.5.3 // indirect - github.com/gookit/goutil v0.6.10 // indirect + github.com/gookit/color v1.5.4 // indirect + github.com/gookit/goutil v0.6.14 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/schema v1.2.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect diff --git a/go.sum b/go.sum index 2be4c65ec..8bfbefde6 100644 --- a/go.sum +++ b/go.sum @@ -1244,8 +1244,8 @@ github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs= github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-yaml v1.11.0 h1:n7Z+zx8S9f9KgzG6KtQKf+kwqXZlLNR2F6018Dgau54= -github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng= +github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ= +github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -1404,12 +1404,12 @@ github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5i github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE= -github.com/gookit/color v1.5.3/go.mod h1:NUzwzeehUfl7GIb36pqId+UGmRfQcU/WiiyTTeNjHtE= -github.com/gookit/config/v2 v2.2.3 h1:GlnYPduYeY7lRgWQmGld9juy0xpFUo06BUC9Pzyjuew= -github.com/gookit/config/v2 v2.2.3/go.mod h1:FhmMu+2wg0UhyOjVGo+DZ1+ov34q4G4aWXzh86boEsY= -github.com/gookit/goutil v0.6.10 h1:iq7CXOf+fYLvrVAh3+ZoLgufGfK65TwbzE8NpnPGtyk= -github.com/gookit/goutil v0.6.10/go.mod h1:qqrPoX+Pm6YmxqqccgkNLPirTFX7UYMES1SK+fokqQU= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gookit/config/v2 v2.2.4 h1:uLHNzFzREe5gDBP4Gb1+WOC9LB6vauPvq4eolp32Dcg= +github.com/gookit/config/v2 v2.2.4/go.mod h1:k1ofSAuJnW6n1kTriFMSzFDC8ZT20tAPQ+1iGI3QOrU= +github.com/gookit/goutil v0.6.14 h1:96elyOG4BvVoDaiT7vx1vHPrVyEtFfYlPPBODR0/FGQ= +github.com/gookit/goutil v0.6.14/go.mod h1:YyDBddefmjS+mU2PDPgCcjVzTDM5WgExiDv5ZA/b8I8= github.com/gookit/ini/v2 v2.2.2 h1:3B8abZJrVH1vi/7TU4STuTBxdhiAq1ORSt6NJZCahaI= github.com/gophercloud/gophercloud v0.15.1-0.20210202035223-633d73521055/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4= github.com/gophercloud/gophercloud v0.16.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4= diff --git a/vendor/github.com/goccy/go-yaml/CHANGELOG.md b/vendor/github.com/goccy/go-yaml/CHANGELOG.md index 2887563f3..c8f820de8 100644 --- a/vendor/github.com/goccy/go-yaml/CHANGELOG.md +++ b/vendor/github.com/goccy/go-yaml/CHANGELOG.md @@ -1,3 +1,26 @@ +# 1.11.2 - 2023-09-15 + +### Fix bugs + +- Fix quoted comments ( #370 ) +- Fix handle of space at start or last ( #376 ) +- Fix sequence with comment ( #390 ) + +# 1.11.1 - 2023-09-14 + +### Fix bugs + +- Handle `\r` in a double-quoted string the same as `\n` ( #372 ) +- Replace loop with n.Values = append(n.Values, target.Values...) ( #380 ) +- Skip encoding an inline field if it is null ( #386 ) +- Fix comment parsing with null value ( #388 ) + +# 1.11.0 - 2023-04-03 + +### Features + +- Supports dynamically switch encode and decode processing for a given type + # 1.10.1 - 2023-03-28 ### Features diff --git a/vendor/github.com/goccy/go-yaml/ast/ast.go b/vendor/github.com/goccy/go-yaml/ast/ast.go index f535a2465..b4d5ec418 100644 --- a/vendor/github.com/goccy/go-yaml/ast/ast.go +++ b/vendor/github.com/goccy/go-yaml/ast/ast.go @@ -1506,9 +1506,7 @@ func (n *SequenceNode) Replace(idx int, value Node) error { func (n *SequenceNode) Merge(target *SequenceNode) { column := n.Start.Position.Column - target.Start.Position.Column target.AddColumn(column) - for _, value := range target.Values { - n.Values = append(n.Values, value) - } + n.Values = append(n.Values, target.Values...) } // SetIsFlowStyle set value to IsFlowStyle field recursively. diff --git a/vendor/github.com/goccy/go-yaml/encode.go b/vendor/github.com/goccy/go-yaml/encode.go index 7d8d81e03..3b9b29814 100644 --- a/vendor/github.com/goccy/go-yaml/encode.go +++ b/vendor/github.com/goccy/go-yaml/encode.go @@ -823,6 +823,10 @@ func (e *Encoder) encodeStruct(ctx context.Context, value reflect.Value, column } mapNode, ok := value.(ast.MapNode) if !ok { + // if an inline field is null, skip encoding it + if _, ok := value.(*ast.NullNode); ok { + continue + } return nil, xerrors.Errorf("inline value is must be map or struct type") } mapIter := mapNode.MapRange() diff --git a/vendor/github.com/goccy/go-yaml/parser/context.go b/vendor/github.com/goccy/go-yaml/parser/context.go index 99f18b184..42cc4f8fa 100644 --- a/vendor/github.com/goccy/go-yaml/parser/context.go +++ b/vendor/github.com/goccy/go-yaml/parser/context.go @@ -13,7 +13,6 @@ type context struct { idx int size int tokens token.Tokens - mode Mode path string } @@ -56,7 +55,6 @@ func (c *context) copy() *context { idx: c.idx, size: c.size, tokens: append(token.Tokens{}, c.tokens...), - mode: c.mode, path: c.path, } } @@ -145,10 +143,6 @@ func (c *context) afterNextNotCommentToken() *token.Token { return nil } -func (c *context) enabledComment() bool { - return c.mode&ParseComments != 0 -} - func (c *context) isCurrentCommentToken() bool { tk := c.currentToken() if tk == nil { @@ -193,7 +187,6 @@ func newContext(tokens token.Tokens, mode Mode) *context { idx: 0, size: len(filteredTokens), tokens: token.Tokens(filteredTokens), - mode: mode, path: "$", } } diff --git a/vendor/github.com/goccy/go-yaml/parser/parser.go b/vendor/github.com/goccy/go-yaml/parser/parser.go index 568e6ad42..13ada50f9 100644 --- a/vendor/github.com/goccy/go-yaml/parser/parser.go +++ b/vendor/github.com/goccy/go-yaml/parser/parser.go @@ -156,15 +156,38 @@ func (p *parser) createMapValueNode(ctx *context, key ast.MapKeyNode, colonToken ctx.insertToken(ctx.idx, nullToken) return ast.Null(nullToken), nil } - + var comment *ast.CommentGroupNode + if tk.Type == token.CommentType { + comment = p.parseCommentOnly(ctx) + if comment != nil { + comment.SetPath(ctx.withChild(key.GetToken().Value).path) + } + tk = ctx.currentToken() + } if tk.Position.Column == key.GetToken().Position.Column && tk.Type == token.StringType { // in this case, // ---- // key: // next + nullToken := p.createNullToken(colonToken) ctx.insertToken(ctx.idx, nullToken) - return ast.Null(nullToken), nil + nullNode := ast.Null(nullToken) + + if comment != nil { + nullNode.SetComment(comment) + } else { + // If there is a comment, it is already bound to the key node, + // so remove the comment from the key to bind it to the null value. + keyComment := key.GetComment() + if keyComment != nil { + if err := key.SetComment(nil); err != nil { + return nil, err + } + nullNode.SetComment(keyComment) + } + } + return nullNode, nil } if tk.Position.Column < key.GetToken().Position.Column { @@ -174,13 +197,20 @@ func (p *parser) createMapValueNode(ctx *context, key ast.MapKeyNode, colonToken // next nullToken := p.createNullToken(colonToken) ctx.insertToken(ctx.idx, nullToken) - return ast.Null(nullToken), nil + nullNode := ast.Null(nullToken) + if comment != nil { + nullNode.SetComment(comment) + } + return nullNode, nil } value, err := p.parseToken(ctx, ctx.currentToken()) if err != nil { return nil, errors.Wrapf(err, "failed to parse mapping 'value' node") } + if comment != nil { + value.SetComment(comment) + } return value, nil } @@ -304,10 +334,9 @@ func (p *parser) parseSequenceEntry(ctx *context) (*ast.SequenceNode, error) { if tk.Type == token.CommentType { comment = p.parseCommentOnly(ctx) tk = ctx.currentToken() - if tk.Type != token.SequenceEntryType { - break + if tk.Type == token.SequenceEntryType { + ctx.progress(1) // skip sequence token } - ctx.progress(1) // skip sequence token } value, err := p.parseToken(ctx.withIndex(uint(len(sequenceNode.Values))), ctx.currentToken()) if err != nil { diff --git a/vendor/github.com/goccy/go-yaml/path.go b/vendor/github.com/goccy/go-yaml/path.go index 7a0c3b115..72554bd8b 100644 --- a/vendor/github.com/goccy/go-yaml/path.go +++ b/vendor/github.com/goccy/go-yaml/path.go @@ -500,11 +500,29 @@ func newSelectorNode(selector string) *selectorNode { } func (n *selectorNode) filter(node ast.Node) (ast.Node, error) { + selector := n.selector + if len(selector) > 1 && selector[0] == '\'' && selector[len(selector)-1] == '\'' { + selector = selector[1 : len(selector)-1] + } switch node.Type() { case ast.MappingType: for _, value := range node.(*ast.MappingNode).Values { key := value.Key.GetToken().Value - if key == n.selector { + if len(key) > 0 { + switch key[0] { + case '"': + var err error + key, err = strconv.Unquote(key) + if err != nil { + return nil, errors.Wrapf(err, "failed to unquote") + } + case '\'': + if len(key) > 1 && key[len(key)-1] == '\'' { + key = key[1 : len(key)-1] + } + } + } + if key == selector { if n.child == nil { return value.Value, nil } @@ -518,7 +536,7 @@ func (n *selectorNode) filter(node ast.Node) (ast.Node, error) { case ast.MappingValueType: value := node.(*ast.MappingValueNode) key := value.Key.GetToken().Value - if key == n.selector { + if key == selector { if n.child == nil { return value.Value, nil } @@ -571,7 +589,9 @@ func (n *selectorNode) replace(node ast.Node, target ast.Node) error { } func (n *selectorNode) String() string { - s := fmt.Sprintf(".%s", n.selector) + var builder PathBuilder + selector := builder.normalizeSelectorName(n.selector) + s := fmt.Sprintf(".%s", selector) if n.child != nil { s += n.child.String() } diff --git a/vendor/github.com/goccy/go-yaml/scanner/scanner.go b/vendor/github.com/goccy/go-yaml/scanner/scanner.go index ce9c6654e..b0eac48d2 100644 --- a/vendor/github.com/goccy/go-yaml/scanner/scanner.go +++ b/vendor/github.com/goccy/go-yaml/scanner/scanner.go @@ -339,6 +339,11 @@ func (s *Scanner) scanDoubleQuote(ctx *Context) (tk *token.Token, pos int) { value = append(value, '\n') idx++ continue + case 'r': + ctx.addOriginBuf(nextChar) + value = append(value, '\r') + idx++ + continue case 'v': ctx.addOriginBuf(nextChar) value = append(value, '\v') diff --git a/vendor/github.com/goccy/go-yaml/token/token.go b/vendor/github.com/goccy/go-yaml/token/token.go index 182f4bea9..c86caab24 100644 --- a/vendor/github.com/goccy/go-yaml/token/token.go +++ b/vendor/github.com/goccy/go-yaml/token/token.go @@ -623,12 +623,12 @@ func IsNeedQuoted(value string) bool { } first := value[0] switch first { - case '*', '&', '[', '{', '}', ']', ',', '!', '|', '>', '%', '\'', '"', '@': + case '*', '&', '[', '{', '}', ']', ',', '!', '|', '>', '%', '\'', '"', '@', ' ': return true } last := value[len(value)-1] switch last { - case ':': + case ':', ' ': return true } if looksLikeTimeValue(value) { diff --git a/vendor/github.com/goccy/go-yaml/yaml.go b/vendor/github.com/goccy/go-yaml/yaml.go index 2e541d855..25b1056fe 100644 --- a/vendor/github.com/goccy/go-yaml/yaml.go +++ b/vendor/github.com/goccy/go-yaml/yaml.go @@ -89,43 +89,42 @@ func (s MapSlice) ToMap() map[interface{}]interface{} { // // The field tag format accepted is: // -// `(...) yaml:"[][,[,]]" (...)` +// `(...) yaml:"[][,[,]]" (...)` // // The following flags are currently supported: // -// omitempty Only include the field if it's not set to the zero -// value for the type or to empty slices or maps. -// Zero valued structs will be omitted if all their public -// fields are zero, unless they implement an IsZero -// method (see the IsZeroer interface type), in which -// case the field will be included if that method returns true. +// omitempty Only include the field if it's not set to the zero +// value for the type or to empty slices or maps. +// Zero valued structs will be omitted if all their public +// fields are zero, unless they implement an IsZero +// method (see the IsZeroer interface type), in which +// case the field will be included if that method returns true. // -// flow Marshal using a flow style (useful for structs, -// sequences and maps). +// flow Marshal using a flow style (useful for structs, +// sequences and maps). // -// inline Inline the field, which must be a struct or a map, -// causing all of its fields or keys to be processed as if -// they were part of the outer struct. For maps, keys must -// not conflict with the yaml keys of other struct fields. +// inline Inline the field, which must be a struct or a map, +// causing all of its fields or keys to be processed as if +// they were part of the outer struct. For maps, keys must +// not conflict with the yaml keys of other struct fields. // -// anchor Marshal with anchor. If want to define anchor name explicitly, use anchor=name style. -// Otherwise, if used 'anchor' name only, used the field name lowercased as the anchor name +// anchor Marshal with anchor. If want to define anchor name explicitly, use anchor=name style. +// Otherwise, if used 'anchor' name only, used the field name lowercased as the anchor name // -// alias Marshal with alias. If want to define alias name explicitly, use alias=name style. -// Otherwise, If omitted alias name and the field type is pointer type, -// assigned anchor name automatically from same pointer address. +// alias Marshal with alias. If want to define alias name explicitly, use alias=name style. +// Otherwise, If omitted alias name and the field type is pointer type, +// assigned anchor name automatically from same pointer address. // // In addition, if the key is "-", the field is ignored. // // For example: // -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" -// yaml.Marshal(&T{F: 1}) // Returns "a: 1\nb: 0\n" -// +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" +// yaml.Marshal(&T{F: 1}) // Returns "a: 1\nb: 0\n" func Marshal(v interface{}) ([]byte, error) { return MarshalWithOptions(v) } @@ -167,16 +166,15 @@ func ValueToNode(v interface{}, opts ...EncodeOption) (ast.Node, error) { // // For example: // -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// var t T -// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// var t T +// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) // // See the documentation of Marshal for the format of tags and a list of // supported tag options. -// func Unmarshal(data []byte, v interface{}) error { return UnmarshalWithOptions(data, v) } diff --git a/vendor/github.com/gookit/color/color_16.go b/vendor/github.com/gookit/color/color_16.go index 0b70efe44..eda226a15 100644 --- a/vendor/github.com/gookit/color/color_16.go +++ b/vendor/github.com/gookit/color/color_16.go @@ -41,15 +41,27 @@ func (o Opts) String() string { * Basic 16 color definition *************************************************************/ -// Base value for foreground/background color -// base: fg 30~37, bg 40~47 -// light: fg 90~97, bg 100~107 +const ( + // OptMax max option value. range: 0 - 9 + OptMax = 10 + // DiffFgBg diff foreground and background color + DiffFgBg = 10 +) + +// Boundary value for foreground/background color 16 +// +// - base: fg 30~37, bg 40~47 +// - light: fg 90~97, bg 100~107 const ( FgBase uint8 = 30 + FgMax uint8 = 37 BgBase uint8 = 40 + BgMax uint8 = 47 HiFgBase uint8 = 90 + HiFgMax uint8 = 97 HiBgBase uint8 = 100 + HiBgMax uint8 = 107 ) // Foreground colors. basic foreground colors 30 - 37 @@ -94,7 +106,7 @@ const ( BgDefault Color = 49 ) -// Extra background color 100 - 107(非标准) +// Extra background color 100 - 107 (non-standard) const ( BgDarkGray Color = iota + 100 BgLightRed @@ -108,7 +120,7 @@ const ( BgGray Color = 100 ) -// Option settings +// Option settings. range: 0 - 9 const ( OpReset Color = iota // 0 重置所有设置 OpBold // 1 加粗 @@ -248,9 +260,9 @@ func (c Color) Println(a ...any) { doPrintlnV2(c.String(), a) } // lightCyan := Cyan.Light() // lightCyan.Print("message") func (c Color) Light() Color { - val := int(c) + val := uint8(c) if val >= 30 && val <= 47 { - return Color(uint8(c) + 60) + return Color(val + 60) } // don't change @@ -264,9 +276,9 @@ func (c Color) Light() Color { // cyan := LightCyan.Darken() // cyan.Print("message") func (c Color) Darken() Color { - val := int(c) + val := uint8(c) if val >= 90 && val <= 107 { - return Color(uint8(c) - 60) + return Color(val - 60) } // don't change @@ -324,7 +336,7 @@ func (c Color) RGB() RGBColor { return emptyRGBColor } - return HEX(Basic2hex(val)) + return HEX(Basic2hex(val), c.IsBg()) } // Code convert to code string. eg "35" @@ -337,8 +349,23 @@ func (c Color) String() string { return strconv.FormatInt(int64(c), 10) } +// IsBg check is background color +func (c Color) IsBg() bool { + val := uint8(c) + return val >= BgBase && val <= BgMax || val >= HiBgBase && val <= HiBgMax +} + +// IsFg check is foreground color +func (c Color) IsFg() bool { + val := uint8(c) + return val >= FgBase && val <= FgMax || val >= HiFgBase && val <= HiFgMax +} + +// IsOption check is option code: 0-9 +func (c Color) IsOption() bool { return uint8(c) < OptMax } + // IsValid color value -func (c Color) IsValid() bool { return c < 107 } +func (c Color) IsValid() bool { return uint8(c) < HiBgMax } /************************************************************* * basic color maps diff --git a/vendor/github.com/gookit/color/color_256.go b/vendor/github.com/gookit/color/color_256.go index 991e604c0..79ae5f8df 100644 --- a/vendor/github.com/gookit/color/color_256.go +++ b/vendor/github.com/gookit/color/color_256.go @@ -43,7 +43,8 @@ const ( * 8bit(256) Color: Bit8Color Color256 *************************************************************/ -// Color256 256 color (8 bit), uint8 range at 0 - 255 +// Color256 256 color (8 bit), uint8 range at 0 - 255. +// Support 256 color on windows CMD, PowerShell // // 颜色值使用10进制和16进制都可 0x98 = 152 // @@ -54,10 +55,9 @@ const ( // // example: // -// fg color: [152, 0] -// bg color: [152, 1] +// fg color: [152, 0] +// bg color: [152, 1] // -// NOTICE: now support 256 color on windows CMD, PowerShell // lint warn - Name starts with package name type Color256 [2]uint8 type Bit8Color = Color256 // alias @@ -164,9 +164,7 @@ func (c Color256) String() string { } // IsFg color -func (c Color256) IsFg() bool { - return c[1] == AsFg -} +func (c Color256) IsFg() bool { return c[1] == AsFg } // ToFg 256 color func (c Color256) ToFg() Color256 { @@ -175,9 +173,7 @@ func (c Color256) ToFg() Color256 { } // IsBg color -func (c Color256) IsBg() bool { - return c[1] == AsBg -} +func (c Color256) IsBg() bool { return c[1] == AsBg } // ToBg 256 color func (c Color256) ToBg() Color256 { @@ -186,9 +182,7 @@ func (c Color256) ToBg() Color256 { } // IsEmpty value -func (c Color256) IsEmpty() bool { - return c[1] > 1 -} +func (c Color256) IsEmpty() bool { return c[1] > 1 } /************************************************************* * 8bit(256) Style diff --git a/vendor/github.com/gookit/color/color_rgb.go b/vendor/github.com/gookit/color/color_rgb.go index 724cf6659..bc129b715 100644 --- a/vendor/github.com/gookit/color/color_rgb.go +++ b/vendor/github.com/gookit/color/color_rgb.go @@ -44,6 +44,7 @@ const ( *************************************************************/ // RGBColor definition. +// Support RGB color on Windows CMD, PowerShell // // The first to third digits represent the color value. // The last digit represents the foreground(0), background(1), >1 is unset value @@ -54,8 +55,6 @@ const ( // // 3rd: Fg=0, Bg=1, >1: unset value // RGBColor{30,144,255, 0} // RGBColor{30,144,255, 1} -// -// NOTICE: now support RGB color on Windows CMD, PowerShell type RGBColor [4]uint8 // create an empty RGBColor @@ -251,6 +250,18 @@ func (c RGBColor) String() string { return "" } +// ToBg convert to background color +func (c RGBColor) ToBg() RGBColor { + c[3] = AsBg + return c +} + +// ToFg convert to foreground color +func (c RGBColor) ToFg() RGBColor { + c[3] = AsFg + return c +} + // IsEmpty value func (c RGBColor) IsEmpty() bool { return c[3] > AsBg diff --git a/vendor/github.com/gookit/color/convert.go b/vendor/github.com/gookit/color/convert.go index 39aac7d2e..c71035360 100644 --- a/vendor/github.com/gookit/color/convert.go +++ b/vendor/github.com/gookit/color/convert.go @@ -52,6 +52,7 @@ var ( // ---------- basic(16) <=> RGB color convert ---------- // refer from Hyper app + // Tip: only keep foreground color, background color need convert to foreground color for convert to RGB basic2hexMap = map[uint8]string{ 30: "000000", // black 31: "c51e14", // red @@ -61,7 +62,7 @@ var ( 35: "c839c5", // magenta 36: "20c5c6", // cyan 37: "c7c7c7", // white - // - don't add bg color + // - don't add bg color, convert to fg color for convert to RGB // 40: "000000", // black // 41: "c51e14", // red // 42: "1dc121", // green @@ -428,10 +429,11 @@ func HexToRGB(hex string) []int { return HexToRgb(hex) } // HexToRgb convert hex color string to RGB numbers // // Usage: -// rgb := HexToRgb("ccc") // rgb: [204 204 204] -// rgb := HexToRgb("aabbcc") // rgb: [170 187 204] -// rgb := HexToRgb("#aabbcc") // rgb: [170 187 204] -// rgb := HexToRgb("0xad99c0") // rgb: [170 187 204] +// +// rgb := HexToRgb("ccc") // rgb: [204 204 204] +// rgb := HexToRgb("aabbcc") // rgb: [170 187 204] +// rgb := HexToRgb("#aabbcc") // rgb: [170 187 204] +// rgb := HexToRgb("0xad99c0") // rgb: [170 187 204] func HexToRgb(hex string) (rgb []int) { hex = strings.TrimSpace(hex) if hex == "" { @@ -474,6 +476,7 @@ func Rgb2hex(rgb []int) string { return RgbToHex(rgb) } // RgbToHex convert RGB-code to hex-code // // Usage: +// // hex := RgbToHex([]int{170, 187, 204}) // hex: "aabbcc" func RgbToHex(rgb []int) string { hexNodes := make([]string, len(rgb)) @@ -488,10 +491,15 @@ func RgbToHex(rgb []int) string { * 4bit(16) color <=> RGB/True color *************************************************************/ +// BasicToHex convert basic color to hex string. +func BasicToHex(val uint8) string { + val = Bg2Fg(val) + return basic2hexMap[val] +} + // Basic2hex convert basic color to hex string. func Basic2hex(val uint8) string { - val = Fg2Bg(val) - return basic2hexMap[val] + return BasicToHex(val) } // Hex2basic convert hex string to basic color code. @@ -663,6 +671,7 @@ func C256ToRgbV1(val uint8) (rgb []uint8) { // returns r, g, and b in the set [0, 255]. // // Usage: +// // HslIntToRgb(0, 100, 50) // red // HslIntToRgb(120, 100, 50) // lime // HslIntToRgb(120, 100, 25) // dark green @@ -677,6 +686,7 @@ func HslIntToRgb(h, s, l int) (rgb []uint8) { // returns r, g, and b in the set [0, 255]. // // Usage: +// // rgbVals := HslToRgb(0, 1, 0.5) // red func HslToRgb(h, s, l float64) (rgb []uint8) { var r, g, b float64 diff --git a/vendor/github.com/gookit/color/style.go b/vendor/github.com/gookit/color/style.go index a009d1d6e..353d39f10 100644 --- a/vendor/github.com/gookit/color/style.go +++ b/vendor/github.com/gookit/color/style.go @@ -37,7 +37,8 @@ func (s *Style) Add(cs ...Color) { *s = append(*s, cs...) } -// Render render text +// Render colored text +// // Usage: // // color.New(color.FgGreen).Render("text") @@ -46,8 +47,9 @@ func (s Style) Render(a ...any) string { return RenderCode(s.String(), a...) } -// Renderln render text line. +// Renderln render text with newline. // like Println, will add spaces for each argument +// // Usage: // // color.New(color.FgGreen).Renderln("text", "more") diff --git a/vendor/github.com/gookit/config/v2/export.go b/vendor/github.com/gookit/config/v2/export.go index 4917cb54c..d6e7c573c 100644 --- a/vendor/github.com/gookit/config/v2/export.go +++ b/vendor/github.com/gookit/config/v2/export.go @@ -76,10 +76,21 @@ func (c *Config) MapOnExists(key string, dst any) error { // // dbInfo := Db{} // config.Structure("db", &dbInfo) -func (c *Config) Structure(key string, dst any) error { +func (c *Config) Structure(key string, dst any) (err error) { var data any - // binding all data + // binding all data on key is empty. if key == "" { + // fix: if c.data is nil, don't need to apply map structure + if len(c.data) == 0 { + // init default value by tag: default + if c.opts.ParseDefault { + err = structs.InitDefaults(dst, func(opt *structs.InitOptions) { + opt.ParseEnv = c.opts.ParseEnv + }) + } + return + } + data = c.data } else { // binding sub-data of the config @@ -90,6 +101,7 @@ func (c *Config) Structure(key string, dst any) error { } } + // map structure from data bindConf := c.opts.makeDecoderConfig() // set result struct ptr bindConf.Result = dst diff --git a/vendor/github.com/gookit/config/v2/read.go b/vendor/github.com/gookit/config/v2/read.go index 246a2943c..449f045ba 100644 --- a/vendor/github.com/gookit/config/v2/read.go +++ b/vendor/github.com/gookit/config/v2/read.go @@ -99,6 +99,21 @@ func (c *Config) Data() map[string]any { return c.data } +// Sub return sub config data by key +func Sub(key string) map[string]any { return dc.Sub(key) } + +// Sub get sub config data by key +// +// Note: will don't apply any options, like ParseEnv +func (c *Config) Sub(key string) map[string]any { + if mp, ok := c.GetValue(key); ok { + if mmp, ok := mp.(map[string]any); ok { + return mmp + } + } + return nil +} + // Keys return all config data func Keys() []string { return dc.Keys() } diff --git a/vendor/github.com/gookit/config/v2/util.go b/vendor/github.com/gookit/config/v2/util.go index bfb597d39..f4472c0b0 100644 --- a/vendor/github.com/gookit/config/v2/util.go +++ b/vendor/github.com/gookit/config/v2/util.go @@ -18,16 +18,21 @@ func ValDecodeHookFunc(parseEnv, parseTime bool) mapstructure.DecodeHookFunc { return data, nil } + var err error str := data.(string) if parseEnv { - str = envutil.ParseEnvValue(str) + // https://docs.docker.com/compose/environment-variables/env-file/ + str, err = envutil.ParseOrErr(str) + if err != nil { + return nil, err + } } if len(str) < 2 { return str, nil } // start char is number(1-9) - if str[0] > '0' && str[0] < '9' { + if str[0] > '0' && str[0] <= '9' { // parse time string. eg: 10s if parseTime && t.Kind() == reflect.Int64 { dur, err := time.ParseDuration(str) diff --git a/vendor/github.com/gookit/goutil/.gitignore b/vendor/github.com/gookit/goutil/.gitignore index 596754e84..7649f9431 100644 --- a/vendor/github.com/gookit/goutil/.gitignore +++ b/vendor/github.com/gookit/goutil/.gitignore @@ -20,3 +20,4 @@ .DS_Store testdata/ +vendor/ \ No newline at end of file diff --git a/vendor/github.com/gookit/goutil/README.md b/vendor/github.com/gookit/goutil/README.md index cbd0cdeef..b9747fa47 100644 --- a/vendor/github.com/gookit/goutil/README.md +++ b/vendor/github.com/gookit/goutil/README.md @@ -7,48 +7,51 @@ [![Coverage Status](https://coveralls.io/repos/github/gookit/goutil/badge.svg?branch=master)](https://coveralls.io/github/gookit/goutil?branch=master) [![Go Reference](https://pkg.go.dev/badge/github.com/gookit/goutil.svg)](https://pkg.go.dev/github.com/gookit/goutil) -💪 Useful utils(**600+**) package for the Go: int, string, array/slice, map, error, time, format, CLI, ENV, filesystem, system, testing and more. +💪 Useful utils(**700+**) package for the Go: int, string, array/slice, map, error, time, format, CLI, ENV, filesystem, system, testing and more. > **[中文说明](README.zh-CN.md)** **Basic packages:** -- [`arrutil`](./arrutil): Array/Slice util functions. eg: check, convert, formatting, enum, collections -- [`cliutil`](./cliutil) Command-line util functions. eg: colored print, read input, exec command -- [`envutil`](./envutil) ENV util for current runtime env information. eg: get one, get info, parse var -- [`fmtutil`](./fmtutil) Format data util functions. eg: data, size, time -- [`fsutil`](./fsutil) Filesystem util functions, quick create, read and write file. eg: file and dir check, operate -- [`jsonutil`](./jsonutil) Provide some util functions for quick read, write, encode, decode JSON data. -- [`maputil`](./maputil) Map data util functions. eg: convert, sub-value get, simple merge -- [`mathutil`](./mathutil) Math(int, number) util functions. eg: convert, math calc, random -- `netutil` Network util functions -- [`reflects`](./reflects) Provide extends reflect util functions. -- [`stdutil`](./stdutil) Provide some commonly std util functions. -- [`structs`](./structs) Provide some extends util functions for struct. eg: tag parse, struct data init -- [`strutil`](./strutil) String util functions. eg: bytes, check, convert, encode, format and more -- [`sysutil`](./sysutil) System util functions. eg: sysenv, exec, user, process +- [`arrutil`](arrutil): Array/Slice util functions. eg: check, convert, formatting, enum, collections +- [`cliutil`](cliutil) Command-line util functions. eg: colored print, read input, exec command +- [`envutil`](envutil) ENV util for current runtime env information. eg: get one, get info, parse var +- [`fmtutil`](fmtutil) Format data util functions. eg: data, size, time +- [`fsutil`](fsutil) Filesystem util functions, quick create, read and write file. eg: file and dir check, operate +- [`goinfo`](goinfo) provide some standard util functions for go. +- [`jsonutil`](jsonutil) Provide some util functions for quick read, write, encode, decode JSON data. +- [`maputil`](maputil) Map data util functions. eg: convert, sub-value get, simple merge +- [`mathutil`](mathutil) Math(int, number) util functions. eg: convert, math calc, random +- [`netutil`](netutil) Network util functions. eg: Ip, IpV4, IpV6, Mac, Port, Hostname, etc. +- [`reflects`](reflects) Provide extends reflect util functions. +- [`structs`](structs) Provide some extends util functions for struct. eg: tag parse, struct data init +- [`strutil`](strutil) String util functions. eg: bytes, check, convert, encode, format and more +- [`sysutil`](sysutil) System util functions. eg: sysenv, exec, user, process -**Advance packages:** +**Extra packages:** -- [`cflag`](./cflag): Wraps and extends go `flag.FlagSet` to build simple command line applications +- [`cflag`](cflag): Wraps and extends go `flag.FlagSet` to build simple command line applications - cli util: - - [cmdline](./cliutil/cmdline) Provide cmdline parse, args build to cmdline -- [`dump`](./dump): GO value printing tool. print slice, map will auto wrap each element and display the call location -- [`errorx`](./errorx) Provide an enhanced error implements for go, allow with stacktrace and wrap another error. -- [`finder`](./fsutil/finder) Provides a simple and convenient filedir lookup function, supports filtering, excluding, matching, ignoring, etc. + - [cmdline](cliutil/cmdline) Provide cmdline parse, args build to cmdline +- [`dump`](dump): GO value printing tool. print slice, map will auto wrap each element and display the call location +- [`encodes`](encodes): Provide some encoding/decoding, hash, crypto util functions. eg: base64, hex, etc. +- [`errorx`](errorx) Provide an enhanced error implements for go, allow with stacktrace and wrap another error. +- file util: + - [`finder`](fsutil/finder) Provides a simple and convenient filedir lookup function, supports filtering, excluding, matching, ignoring, etc. - net util: - - [httpreq](netutil/httpreq) An easier-to-use HTTP client that wraps http.Client + - [httpreq](netutil/httpreq) An easier-to-use HTTP client that wraps http.Client, and with some http utils. - string util: - [textscan](strutil/textscan) Implemented a parser that quickly scans and analyzes text content. It can be used to parse INI, Properties and other formats - [textutil](strutil/textutil) Provide some extensions text handle util functions. eg: text replace, etc. +- [syncs](syncs) Provides synchronization primitives util functions. - system util: - - [clipboard](./sysutil/clipboard) Provide a simple clipboard read and write operations. - - [cmdr](./sysutil/cmdr) Provide for quick build and run a cmd, batch run multi cmd tasks - - [process](./sysutil/process) Provide some process handle util functions. + - [clipboard](sysutil/clipboard) Provide a simple clipboard read and write operations. + - [cmdr](sysutil/cmdr) Provide for quick build and run a cmd, batch run multi cmd tasks + - [process](sysutil/process) Provide some process handle util functions. - [`testutil`](testutil) Test help util functions. eg: http test, mock ENV value - [assert](testutil/assert) Provides commonly asserts functions for help testing - [fakeobj](testutil/fakeobj) provides a fake object for testing. such as fake fs.File, fs.FileInfo, fs.DirEntry etc. -- [`timex`](./timex) Provides an enhanced time.Time implementation. Add more commonly used functional methods +- [`timex`](timex) Provides an enhanced time.Time implementation. Add more commonly used functional methods - such as: DayStart(), DayAfter(), DayAgo(), DateFormat() and more. ## Go Doc @@ -83,6 +86,16 @@ i64Val = goutil.Int64("-2") // -2 u64Val = goutil.Uint("2") // 2 ``` +### Dump go variable + +```go +dump.Print(somevar, somevar2, ...) +``` + +**dump nested struct** + +![preview-nested-struct](dump/_examples/preview-nested-struct.png) + ## Packages ### Array and Slice @@ -91,69 +104,82 @@ u64Val = goutil.Uint("2") // 2 ```go // source at arrutil/arrutil.go -func Reverse(ss []string) -func StringsRemove(ss []string, s string) []string -func StringsFilter(ss []string, filter ...func(s string) bool) []string -func StringsMap(ss []string, mapFn func(s string) string) []string -func TrimStrings(ss []string, cutSet ...string) []string -func GetRandomOne[T any](arr []T) T -func RandomOne[T any](arr []T) T -func Unique[T ~string | comdef.XintOrFloat](list []T) []T -func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int +func GetRandomOne[T any](arr []T) T +func RandomOne[T any](arr []T) T // source at arrutil/check.go -func IntsHas(ints []int, val int) bool -func Int64sHas(ints []int64, val int64) bool -func InStrings(elem string, ss []string) bool -func StringsHas(ss []string, val string) bool -func NotIn[T comdef.ScalarType](value T, list []T) bool -func In[T comdef.ScalarType](value T, list []T) bool -func ContainsAll[T comdef.ScalarType](list, values []T) bool -func IsSubList[T comdef.ScalarType](values, list []T) bool -func IsParent[T comdef.ScalarType](values, list []T) bool -func HasValue(arr, val any) bool -func Contains(arr, val any) bool -func NotContains(arr, val any) bool +func SliceHas[T comdef.ScalarType](slice []T, val T) bool +func IntsHas[T comdef.Integer](ints []T, val T) bool +func Int64sHas(ints []int64, val int64) bool +func StringsHas[T ~string](ss []T, val T) bool +func InStrings[T ~string](elem T, ss []T) bool +func NotIn[T comdef.ScalarType](value T, list []T) bool +func In[T comdef.ScalarType](value T, list []T) bool +func ContainsAll[T comdef.ScalarType](list, values []T) bool +func IsSubList[T comdef.ScalarType](values, list []T) bool +func IsParent[T comdef.ScalarType](values, list []T) bool +func HasValue(arr, val any) bool +func Contains(arr, val any) bool +func NotContains(arr, val any) bool // source at arrutil/collection.go -func TwowaySearch(data any, item any, fn Comparer) (int, error) -func MakeEmptySlice(itemType reflect.Type) any -func CloneSlice(data any) any -func Differences[T any](first, second []T, fn Comparer) []T -func Excepts(first, second any, fn Comparer) any -func Intersects(first any, second any, fn Comparer) any -func Union(first, second any, fn Comparer) any -func Find(source any, fn Predicate) (any, error) -func FindOrDefault(source any, fn Predicate, defaultValue any) any -func TakeWhile(data any, fn Predicate) any -func ExceptWhile(data any, fn Predicate) any -// source at arrutil/collection_gte118.go -func Map[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V -func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V +func StringEqualsComparer(a, b string) int +func ValueEqualsComparer[T comdef.Compared](a, b T) int +func ReflectEqualsComparer[T any](a, b T) int +func ElemTypeEqualsComparer[T any](a, b T) int +func TwowaySearch[T any](data []T, item T, fn Comparer[T]) (int, error) +func CloneSlice[T any](data []T) []T +func Diff[T any](first, second []T, fn Comparer[T]) []T +func Differences[T any](first, second []T, fn Comparer[T]) []T +func Excepts[T any](first, second []T, fn Comparer[T]) []T +func Intersects[T any](first, second []T, fn Comparer[T]) []T +func Union[T any](first, second []T, fn Comparer[T]) []T +func Find[T any](source []T, fn Predicate[T]) (v T, err error) +func FindOrDefault[T any](source []T, fn Predicate[T], defaultValue T) T +func TakeWhile[T any](data []T, fn Predicate[T]) []T +func ExceptWhile[T any](data []T, fn Predicate[T]) []T // source at arrutil/convert.go -func JoinStrings(sep string, ss ...string) string -func StringsJoin(sep string, ss ...string) string -func JoinSlice(sep string, arr ...any) string -func ToInt64s(arr any) (ret []int64, err error) -func MustToInt64s(arr any) []int64 -func SliceToInt64s(arr []any) []int64 -func StringsAsInts(ss []string) []int -func StringsToInts(ss []string) (ints []int, err error) -func StringsTryInts(ss []string) (ints []int, err error) -func AnyToSlice(sl any) (ls []any, err error) -func AnyToStrings(arr any) []string -func MustToStrings(arr any) []string -func StringsToSlice(ss []string) []any -func ToStrings(arr any) (ret []string, err error) -func SliceToStrings(arr []any) []string -func QuietStrings(arr []any) []string -func ConvType[T any, R any](arr []T, newElemTyp R) ([]R, error) -func AnyToString(arr any) string -func SliceToString(arr ...any) string -func ToString(arr []any) string -func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V -func CombineToSMap(keys, values []string) map[string]string +func JoinStrings(sep string, ss ...string) string +func StringsJoin(sep string, ss ...string) string +func JoinTyped[T any](sep string, arr ...T) string +func JoinSlice(sep string, arr ...any) string +func IntsToString[T comdef.Integer](ints []T) string +func ToInt64s(arr any) (ret []int64, err error) +func MustToInt64s(arr any) []int64 +func SliceToInt64s(arr []any) []int64 +func AnyToSlice(sl any) (ls []any, err error) +func AnyToStrings(arr any) []string +func MustToStrings(arr any) []string +func ToStrings(arr any) (ret []string, err error) +func SliceToStrings(arr []any) []string +func QuietStrings(arr []any) []string +func ConvType[T any, R any](arr []T, newElemTyp R) ([]R, error) +func AnyToString(arr any) string +func SliceToString(arr ...any) string +func ToString[T any](arr []T) string +func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V +func CombineToSMap(keys, values []string) map[string]string // source at arrutil/format.go -func NewFormatter(arr any) *ArrFormatter -func FormatIndent(arr any, indent string) string +func NewFormatter(arr any) *ArrFormatter +func FormatIndent(arr any, indent string) string +// source at arrutil/process.go +func Reverse[T any](ls []T) +func Remove[T comdef.Compared](ls []T, val T) []T +func Filter[T any](ls []T, filter ...comdef.MatchFunc[T]) []T +func Map[T any, V any](list []T, mapFn MapFn[T, V]) []V +func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V +func Unique[T ~string | comdef.XintOrFloat](list []T) []T +func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int +// source at arrutil/strings.go +func StringsToAnys(ss []string) []any +func StringsToSlice(ss []string) []any +func StringsAsInts(ss []string) []int +func StringsToInts(ss []string) (ints []int, err error) +func StringsTryInts(ss []string) (ints []int, err error) +func StringsUnique(ss []string) []string +func StringsContains(ss []string, s string) bool +func StringsRemove(ss []string, s string) []string +func StringsFilter(ss []string, filter ...comdef.StringMatchFunc) []string +func StringsMap(ss []string, mapFn func(s string) string) []string +func TrimStrings(ss []string, cutSet ...string) []string ``` #### ArrUtil Usage @@ -183,24 +209,30 @@ ss, err := arrutil.ToStrings([]int{1, 2}) // ss: []string{"1", "2"} ```go // source at byteutil/buffer.go -func NewBuffer() *Buffer +func NewBuffer() *Buffer // source at byteutil/byteutil.go -func Random(length int) ([]byte, error) -func FirstLine(bs []byte) []byte -func StrOrErr(bs []byte, err error) (string, error) -func SafeString(bs []byte, err error) string -func String(b []byte) string -func ToString(b []byte) string -func AppendAny(dst []byte, v any) []byte -func Cut(bs []byte, sep byte) (before, after []byte, found bool) -// source at byteutil/bytex.go -func Md5(src any) []byte +func Md5(src any) []byte +func ShortMd5(src any) []byte +func Random(length int) ([]byte, error) +func FirstLine(bs []byte) []byte +func AppendAny(dst []byte, v any) []byte +func Cut(bs []byte, sep byte) (before, after []byte, found bool) +func SafeCut(bs []byte, sep byte) (before, after []byte) +func SafeCuts(bs []byte, sep []byte) (before, after []byte) // source at byteutil/check.go -func IsNumChar(c byte) bool +func IsNumChar(c byte) bool +// source at byteutil/conv.go +func StrOrErr(bs []byte, err error) (string, error) +func SafeString(bs []byte, err error) string +func String(b []byte) string +func ToString(b []byte) string +func ToBytes(v any) ([]byte, error) +func SafeBytes(v any) []byte +func ToBytesWithFunc(v any, usrFn ToBytesFunc) ([]byte, error) // source at byteutil/encoder.go -func NewStdEncoder(encFn func(src []byte) []byte, decFn func(src []byte) ([]byte, error)) *StdEncoder +func NewStdEncoder(encFn BytesEncodeFunc, decFn BytesDecodeFunc) *StdEncoder // source at byteutil/pool.go -func NewChanPool(maxSize int, width int, capWidth int) *ChanPool +func NewChanPool(chSize int, width int, capWidth int) *ChanPool ``` ### Cflag @@ -209,30 +241,34 @@ func NewChanPool(maxSize int, width int, capWidth int) *ChanPool ```go // source at cflag/app.go -func NewApp(fns ...func(app *App)) *App -func NewCmd(name, desc string) *Cmd +func NewApp(fns ...func(app *App)) *App +func NewCmd(name, desc string) *Cmd // source at cflag/cflag.go -func SetDebug(open bool) -func New(fns ...func(c *CFlags)) *CFlags -func NewEmpty(fns ...func(c *CFlags)) *CFlags -func WithDesc(desc string) func(c *CFlags) -func WithVersion(version string) func(c *CFlags) +func SetDebug(open bool) +func New(fns ...func(c *CFlags)) *CFlags +func NewEmpty(fns ...func(c *CFlags)) *CFlags +func WithDesc(desc string) func(c *CFlags) +func WithVersion(version string) func(c *CFlags) // source at cflag/ext.go -func NewEnumString(enum ...string) EnumString -func NewKVString() KVString +func LimitInt(min, max int) comdef.IntCheckFunc +func NewIntVar(checkFn comdef.IntCheckFunc) IntVar +func NewStrVar(checkFn comdef.StrCheckFunc) StrVar +func NewEnumString(enum ...string) EnumString +func NewKVString() KVString +func Value // source at cflag/optarg.go -func NewArg(name, desc string, required bool) *FlagArg +func NewArg(name, desc string, required bool) *FlagArg // source at cflag/util.go -func IsGoodName(name string) bool -func IsZeroValue(opt *flag.Flag, value string) (bool, bool) -func AddPrefix(name string) string -func AddPrefixes(name string, shorts []string) string -func AddPrefixes2(name string, shorts []string, nameAtEnd bool) string -func SplitShortcut(shortcut string) []string -func FilterNames(names []string) []string -func IsFlagHelpErr(err error) bool -func WrapColorForCode(s string) string -func ReplaceShorts(args []string, shortsMap map[string]string) []string +func IsGoodName(name string) bool +func IsZeroValue(opt *flag.Flag, value string) (bool, bool) +func AddPrefix(name string) string +func AddPrefixes(name string, shorts []string) string +func AddPrefixes2(name string, shorts []string, nameAtEnd bool) string +func SplitShortcut(shortcut string) []string +func FilterNames(names []string) []string +func IsFlagHelpErr(err error) bool +func WrapColorForCode(s string) string +func ReplaceShorts(args []string, shortsMap map[string]string) []string ``` #### `cflag` Usage @@ -245,72 +281,39 @@ func ReplaceShorts(args []string, shortsMap map[string]string) []string ```go // source at cliutil/cliutil.go -func LineBuild(binFile string, args []string) string -func BuildLine(binFile string, args []string) string -func String2OSArgs(line string) []string -func StringToOSArgs(line string) []string -func ParseLine(line string) []string -func QuickExec(cmdLine string, workDir ...string) (string, error) -func ExecLine(cmdLine string, workDir ...string) (string, error) -func ExecCmd(binName string, args []string, workDir ...string) (string, error) -func ExecCommand(binName string, args []string, workDir ...string) (string, error) -func ShellExec(cmdLine string, shells ...string) (string, error) -func CurrentShell(onlyName bool) (path string) -func HasShellEnv(shell string) bool -func BuildOptionHelpName(names []string) string -func ShellQuote(s string) string -func OutputLines(output string) []string -// source at cliutil/color_print.go -func Redp(a ...any) -func Redf(format string, a ...any) -func Redln(a ...any) -func Bluep(a ...any) -func Bluef(format string, a ...any) -func Blueln(a ...any) -func Cyanp(a ...any) -func Cyanf(format string, a ...any) -func Cyanln(a ...any) -func Grayp(a ...any) -func Grayf(format string, a ...any) -func Grayln(a ...any) -func Greenp(a ...any) -func Greenf(format string, a ...any) -func Greenln(a ...any) -func Yellowp(a ...any) -func Yellowf(format string, a ...any) -func Yellowln(a ...any) -func Magentap(a ...any) -func Magentaf(format string, a ...any) -func Magentaln(a ...any) -func Infop(a ...any) -func Infof(format string, a ...any) -func Infoln(a ...any) -func Successp(a ...any) -func Successf(format string, a ...any) -func Successln(a ...any) -func Errorp(a ...any) -func Errorf(format string, a ...any) -func Errorln(a ...any) -func Warnp(a ...any) -func Warnf(format string, a ...any) -func Warnln(a ...any) +func SplitMulti(ss []string, sep string) []string +func LineBuild(binFile string, args []string) string +func BuildLine(binFile string, args []string) string +func String2OSArgs(line string) []string +func StringToOSArgs(line string) []string +func ParseLine(line string) []string +func QuickExec(cmdLine string, workDir ...string) (string, error) +func ExecLine(cmdLine string, workDir ...string) (string, error) +func ExecCmd(binName string, args []string, workDir ...string) (string, error) +func ExecCommand(binName string, args []string, workDir ...string) (string, error) +func ShellExec(cmdLine string, shells ...string) (string, error) +func CurrentShell(onlyName bool) (path string) +func HasShellEnv(shell string) bool +func BuildOptionHelpName(names []string) string +func ShellQuote(s string) string +func OutputLines(output string) []string // source at cliutil/info.go -func Workdir() string -func BinDir() string -func BinFile() string -func BinName() string -func GetTermSize(refresh ...bool) (w int, h int) +func Workdir() string +func BinDir() string +func BinFile() string +func BinName() string +func GetTermSize(refresh ...bool) (w int, h int) // source at cliutil/read.go -func ReadInput(question string) (string, error) -func ReadLine(question string) (string, error) -func ReadFirst(question string) (string, error) -func ReadFirstByte(question string) (byte, error) -func ReadFirstRune(question string) (rune, error) -func ReadAsBool(tip string, defVal bool) bool -func ReadPassword(question ...string) string -func Confirm(tip string, defVal ...bool) bool -func InputIsYes(ans string) bool -func ByteIsYes(ans byte) bool +func ReadInput(question string) (string, error) +func ReadLine(question string) (string, error) +func ReadFirst(question string) (string, error) +func ReadFirstByte(question string) (byte, error) +func ReadFirstRune(question string) (rune, error) +func ReadAsBool(tip string, defVal bool) bool +func Confirm(tip string, defVal ...bool) bool +func InputIsYes(ans string) bool +func ByteIsYes(ans byte) bool +func ReadPassword(question ...string) string ``` #### CLI Util Usage @@ -374,30 +377,30 @@ Build line: ./myapp -a val0 -m "this is message" arg0 ```go // source at dump/dump.go -func Std() *Dumper -func Reset() -func Config(fns ...OptionFunc) -func Print(vs ...any) -func Println(vs ...any) -func Fprint(w io.Writer, vs ...any) -func Std2() *Dumper -func Reset2() -func Format(vs ...any) string -func NoLoc(vs ...any) -func Clear(vs ...any) +func Std() *Dumper +func Reset() +func Config(fns ...OptionFunc) +func Print(vs ...any) +func Println(vs ...any) +func Fprint(w io.Writer, vs ...any) +func Std2() *Dumper +func Reset2() +func Format(vs ...any) string +func NoLoc(vs ...any) +func Clear(vs ...any) // source at dump/dumper.go -func NewDumper(out io.Writer, skip int) *Dumper -func NewWithOptions(fns ...OptionFunc) *Dumper +func NewDumper(out io.Writer, skip int) *Dumper +func NewWithOptions(fns ...OptionFunc) *Dumper // source at dump/options.go -func NewDefaultOptions(out io.Writer, skip int) *Options -func SkipNilField() OptionFunc -func SkipPrivate() OptionFunc -func BytesAsString() OptionFunc -func WithCallerSkip(skip int) OptionFunc -func WithoutPosition() OptionFunc -func WithoutOutput(out io.Writer) OptionFunc -func WithoutColor() OptionFunc -func WithoutType() OptionFunc +func NewDefaultOptions(out io.Writer, skip int) *Options +func SkipNilField() OptionFunc +func SkipPrivate() OptionFunc +func BytesAsString() OptionFunc +func WithCallerSkip(skip int) OptionFunc +func WithoutPosition() OptionFunc +func WithoutOutput(out io.Writer) OptionFunc +func WithoutColor() OptionFunc +func WithoutType() OptionFunc ``` #### Examples @@ -443,44 +446,59 @@ Preview: ![](dump/_examples/preview-nested-struct.png) +### Encodes + +> Package `github.com/gookit/goutil/encodes` + +```go +// source at encodes/encodes.go +func B32Encode(str string) string +func B32Decode(str string) string +func B64Encode(str string) string +func B64EncodeBytes(src []byte) []byte +func B64Decode(str string) string +func B64DecodeBytes(str []byte) []byte +``` + ### ENV/Environment > Package `github.com/gookit/goutil/envutil` ```go // source at envutil/envutil.go -func VarReplace(s string) string -func VarParse(val string) string -func ParseEnvValue(val string) string -func ParseValue(val string) (newVal string) -func SetEnvMap(mp map[string]string) -func SetEnvs(kvPairs ...string) -func UnsetEnvs(keys ...string) +func VarReplace(s string) string +func ParseOrErr(val string) (string, error) +func ParseValue(val string) string +func VarParse(val string) string +func ParseEnvValue(val string) string +func SetEnvMap(mp map[string]string) +func SetEnvs(kvPairs ...string) +func UnsetEnvs(keys ...string) // source at envutil/get.go -func Getenv(name string, def ...string) string -func GetInt(name string, def ...int) int -func GetBool(name string, def ...bool) bool -func GetMulti(names ...string) map[string]string -func EnvPaths() []string -func EnvMap() map[string]string -func Environ() map[string]string -func SearchEnvKeys(keywords string) map[string]string -func SearchEnv(keywords string, matchValue bool) map[string]string +func Getenv(name string, def ...string) string +func GetInt(name string, def ...int) int +func GetBool(name string, def ...bool) bool +func GetMulti(names ...string) map[string]string +func EnvPaths() []string +func EnvMap() map[string]string +func Environ() map[string]string +func SearchEnvKeys(keywords string) map[string]string +func SearchEnv(keywords string, matchValue bool) map[string]string // source at envutil/info.go -func IsWin() bool -func IsWindows() bool -func IsMac() bool -func IsLinux() bool -func IsMSys() bool -func IsWSL() bool -func IsTerminal(fd uintptr) bool -func StdIsTerminal() bool -func IsConsole(out io.Writer) bool -func HasShellEnv(shell string) bool -func IsSupportColor() bool -func IsSupport256Color() bool -func IsSupportTrueColor() bool -func IsGithubActions() bool +func IsWin() bool +func IsWindows() bool +func IsMac() bool +func IsLinux() bool +func IsMSys() bool +func IsWSL() bool +func IsTerminal(fd uintptr) bool +func StdIsTerminal() bool +func IsConsole(out io.Writer) bool +func HasShellEnv(shell string) bool +func IsSupportColor() bool +func IsSupport256Color() bool +func IsSupportTrueColor() bool +func IsGithubActions() bool ``` #### ENV Util Usage @@ -510,49 +528,51 @@ Package errorx provide a enhanced error implements, allow with call stack and wr ```go // source at errorx/assert.go -func IsTrue(result bool, fmtAndArgs ...any) error -func IsFalse(result bool, fmtAndArgs ...any) error -func IsIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error -func NotIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error +func IsTrue(result bool, fmtAndArgs ...any) error +func IsFalse(result bool, fmtAndArgs ...any) error +func IsIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error +func NotIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error // source at errorx/errors.go -func NewR(code int, msg string) ErrorR -func Fail(code int, msg string) ErrorR -func Failf(code int, tpl string, v ...any) ErrorR -func Suc(msg string) ErrorR +func NewR(code int, msg string) ErrorR +func Fail(code int, msg string) ErrorR +func Failf(code int, tpl string, v ...any) ErrorR +func Suc(msg string) ErrorR // source at errorx/errorx.go -func New(msg string) error -func Newf(tpl string, vars ...any) error -func Errorf(tpl string, vars ...any) error -func With(err error, msg string) error -func Withf(err error, tpl string, vars ...any) error -func WithPrev(err error, msg string) error -func WithPrevf(err error, tpl string, vars ...any) error -func WithStack(err error) error -func Traced(err error) error -func Stacked(err error) error -func WithOptions(msg string, fns ...func(opt *ErrStackOpt)) error -func Wrap(err error, msg string) error -func Wrapf(err error, tpl string, vars ...any) error +func New(msg string) error +func Newf(tpl string, vars ...any) error +func Errorf(tpl string, vars ...any) error +func With(err error, msg string) error +func Withf(err error, tpl string, vars ...any) error +func WithPrev(err error, msg string) error +func WithPrevf(err error, tpl string, vars ...any) error +func WithStack(err error) error +func Traced(err error) error +func Stacked(err error) error +func WithOptions(msg string, fns ...func(opt *ErrStackOpt)) error +func Wrap(err error, msg string) error +func Wrapf(err error, tpl string, vars ...any) error // source at errorx/stack.go -func FuncForPC(pc uintptr) *Func -func ResetStdOpt() -func Config(fns ...func(opt *ErrStackOpt)) -func SkipDepth(skipDepth int) func(opt *ErrStackOpt) -func TraceDepth(traceDepth int) func(opt *ErrStackOpt) +func FuncForPC(pc uintptr) *Func +func ResetStdOpt() +func Config(fns ...func(opt *ErrStackOpt)) +func SkipDepth(skipDepth int) func(opt *ErrStackOpt) +func TraceDepth(traceDepth int) func(opt *ErrStackOpt) // source at errorx/util.go -func Err(msg string) error -func Raw(msg string) error -func Ef(tpl string, vars ...any) error -func Errf(tpl string, vars ...any) error -func Rawf(tpl string, vars ...any) error -func Cause(err error) error -func Unwrap(err error) error -func Previous(err error) error -func ToErrorX(err error) (ex *ErrorX, ok bool) -func Has(err, target error) bool -func Is(err, target error) bool -func To(err error, target any) bool -func As(err error, target any) bool +func Err(msg string) error +func Raw(msg string) error +func Ef(tpl string, vars ...any) error +func Errf(tpl string, vars ...any) error +func Rawf(tpl string, vars ...any) error +func Cause(err error) error +func Unwrap(err error) error +func Previous(err error) error +func IsErrorX(err error) (ok bool) +func ToErrorX(err error) (ex *ErrorX, ok bool) +func MustEX(err error) *ErrorX +func Has(err, target error) bool +func Is(err, target error) bool +func To(err error, target any) bool +func As(err error, target any) bool ``` #### Errorx Usage @@ -637,17 +657,17 @@ runtime.goexit() ```go // source at fmtutil/fmtutil.go -func StringOrJSON(v any) ([]byte, error) +func StringOrJSON(v any) ([]byte, error) // source at fmtutil/format.go -func DataSize(size uint64) string -func SizeToString(size uint64) string -func StringToByte(sizeStr string) uint64 -func ParseByte(sizeStr string) uint64 -func PrettyJSON(v any) (string, error) -func StringsToInts(ss []string) (ints []int, err error) -func ArgsWithSpaces(vs []any) (message string) +func DataSize(size uint64) string +func SizeToString(size uint64) string +func StringToByte(sizeStr string) uint64 +func ParseByte(sizeStr string) uint64 +func PrettyJSON(v any) (string, error) +func StringsToInts(ss []string) (ints []int, err error) +func ArgsWithSpaces(vs []any) (message string) // source at fmtutil/time.go -func HowLongAgo(sec int64) string +func HowLongAgo(sec int64) string ``` ### File System @@ -656,96 +676,118 @@ func HowLongAgo(sec int64) string ```go // source at fsutil/check.go -func PathExists(path string) bool -func IsDir(path string) bool -func FileExists(path string) bool -func IsFile(path string) bool -func IsAbsPath(aPath string) bool -func IsImageFile(path string) bool -func IsZipFile(filepath string) bool -func PathMatch(pattern, s string) bool +func PathExists(path string) bool +func IsDir(path string) bool +func FileExists(path string) bool +func IsFile(path string) bool +func IsAbsPath(aPath string) bool +func IsEmptyDir(dirPath string) bool +func IsImageFile(path string) bool +func IsZipFile(filepath string) bool +func PathMatch(pattern, s string) bool +// source at fsutil/define.go +func NewEntry(fPath string, ent fs.DirEntry) Entry +func NewFileInfo(fPath string, info fs.FileInfo) FileInfo // source at fsutil/find.go -func SearchNameUp(dirPath, name string) string -func SearchNameUpx(dirPath, name string) (string, bool) -func WalkDir(dir string, fn fs.WalkDirFunc) error -func Glob(pattern string, fls ...comdef.StringMatchFunc) []string -func GlobWithFunc(pattern string, fn func(filePath string) error) (err error) -func OnlyFindDir(_ string, ent fs.DirEntry) bool -func OnlyFindFile(_ string, ent fs.DirEntry) bool -func ExcludeNames(names ...string) FilterFunc -func IncludeSuffix(ss ...string) FilterFunc -func ExcludeDotFile(_ string, ent fs.DirEntry) bool -func ExcludeSuffix(ss ...string) FilterFunc -func ApplyFilters(fPath string, ent fs.DirEntry, filters []FilterFunc) bool -func FindInDir(dir string, handleFn HandleFunc, filters ...FilterFunc) (e error) +func FilePathInDirs(file string, dirs ...string) string +func FirstExists(paths ...string) string +func FirstExistsDir(paths ...string) string +func FirstExistsFile(paths ...string) string +func MatchPaths(paths []string, matcher PathMatchFunc) []string +func MatchFirst(paths []string, matcher PathMatchFunc, defaultPath string) string +func SearchNameUp(dirPath, name string) string +func SearchNameUpx(dirPath, name string) (string, bool) +func WalkDir(dir string, fn fs.WalkDirFunc) error +func Glob(pattern string, fls ...NameMatchFunc) []string +func GlobWithFunc(pattern string, fn func(filePath string) error) (err error) +func OnlyFindDir(_ string, ent fs.DirEntry) bool +func OnlyFindFile(_ string, ent fs.DirEntry) bool +func ExcludeNames(names ...string) FilterFunc +func IncludeSuffix(ss ...string) FilterFunc +func ExcludeDotFile(_ string, ent fs.DirEntry) bool +func ExcludeSuffix(ss ...string) FilterFunc +func ApplyFilters(fPath string, ent fs.DirEntry, filters []FilterFunc) bool +func FindInDir(dir string, handleFn HandleFunc, filters ...FilterFunc) (e error) // source at fsutil/fsutil.go -func OSTempFile(pattern string) (*os.File, error) -func TempFile(dir, pattern string) (*os.File, error) -func OSTempDir(pattern string) (string, error) -func TempDir(dir, pattern string) (string, error) -func MimeType(path string) (mime string) -func ReaderMimeType(r io.Reader) (mime string) -func JoinPaths(elem ...string) string -func JoinSubPaths(basePath string, elem ...string) string -func SlashPath(path string) string -func UnixPath(path string) string -func ToAbsPath(p string) string +func JoinPaths(elem ...string) string +func JoinSubPaths(basePath string, elem ...string) string +func SlashPath(path string) string +func UnixPath(path string) string +func ToAbsPath(p string) string // source at fsutil/info.go -func Dir(fpath string) string -func PathName(fpath string) string -func Name(fpath string) string -func FileExt(fpath string) string -func Extname(fpath string) string -func Suffix(fpath string) string -func Expand(pathStr string) string -func ExpandPath(pathStr string) string -func ResolvePath(pathStr string) string -func SplitPath(pathStr string) (dir, name string) +func DirPath(fpath string) string +func Dir(fpath string) string +func PathName(fpath string) string +func Name(fpath string) string +func FileExt(fpath string) string +func Extname(fpath string) string +func Suffix(fpath string) string +func Expand(pathStr string) string +func ExpandPath(pathStr string) string +func ResolvePath(pathStr string) string +func SplitPath(pathStr string) (dir, name string) // source at fsutil/info_nonwin.go -func Realpath(pathStr string) string +func Realpath(pathStr string) string +// source at fsutil/mime.go +func DetectMime(path string) string +func MimeType(path string) (mime string) +func ReaderMimeType(r io.Reader) (mime string) // source at fsutil/operate.go -func Mkdir(dirPath string, perm os.FileMode) error -func MkDirs(perm os.FileMode, dirPaths ...string) error -func MkSubDirs(perm os.FileMode, parentDir string, subDirs ...string) error -func MkParentDir(fpath string) error -func OpenFile(filepath string, flag int, perm os.FileMode) (*os.File, error) -func MustOpenFile(filepath string, flag int, perm os.FileMode) *os.File -func QuickOpenFile(filepath string, fileFlag ...int) (*os.File, error) -func OpenAppendFile(filepath string, filePerm ...os.FileMode) (*os.File, error) -func OpenTruncFile(filepath string, filePerm ...os.FileMode) (*os.File, error) -func OpenReadFile(filepath string) (*os.File, error) -func CreateFile(fpath string, filePerm, dirPerm os.FileMode, fileFlag ...int) (*os.File, error) -func MustCreateFile(filePath string, filePerm, dirPerm os.FileMode) *os.File -func Remove(fPath string) error -func MustRemove(fPath string) -func QuietRemove(fPath string) -func RmIfExist(fPath string) error -func DeleteIfExist(fPath string) error -func RmFileIfExist(fPath string) error -func DeleteIfFileExist(fPath string) error -func RemoveSub(dirPath string, fns ...FilterFunc) error -func Unzip(archive, targetDir string) (err error) +func Mkdir(dirPath string, perm os.FileMode) error +func MkDirs(perm os.FileMode, dirPaths ...string) error +func MkSubDirs(perm os.FileMode, parentDir string, subDirs ...string) error +func MkParentDir(fpath string) error +func NewOpenOption(optFns ...OpenOptionFunc) *OpenOption +func OpenOptOrNew(opt *OpenOption) *OpenOption +func WithFlag(flag int) OpenOptionFunc +func WithPerm(perm os.FileMode) OpenOptionFunc +func OpenFile(filePath string, flag int, perm os.FileMode) (*os.File, error) +func MustOpenFile(filePath string, flag int, perm os.FileMode) *os.File +func QuickOpenFile(filepath string, fileFlag ...int) (*os.File, error) +func OpenAppendFile(filepath string, filePerm ...os.FileMode) (*os.File, error) +func OpenTruncFile(filepath string, filePerm ...os.FileMode) (*os.File, error) +func OpenReadFile(filepath string) (*os.File, error) +func CreateFile(fpath string, filePerm, dirPerm os.FileMode, fileFlag ...int) (*os.File, error) +func MustCreateFile(filePath string, filePerm, dirPerm os.FileMode) *os.File +func Remove(fPath string) error +func MustRemove(fPath string) +func QuietRemove(fPath string) +func SafeRemoveAll(path string) +func RmIfExist(fPath string) error +func DeleteIfExist(fPath string) error +func RmFileIfExist(fPath string) error +func DeleteIfFileExist(fPath string) error +func RemoveSub(dirPath string, fns ...FilterFunc) error +func Unzip(archive, targetDir string) (err error) // source at fsutil/opread.go -func NewIOReader(in any) (r io.Reader, err error) -func DiscardReader(src io.Reader) -func ReadFile(filePath string) []byte -func MustReadFile(filePath string) []byte -func ReadReader(r io.Reader) []byte -func MustReadReader(r io.Reader) []byte -func ReadString(in any) string -func ReadStringOrErr(in any) (string, error) -func ReadAll(in any) []byte -func GetContents(in any) []byte -func ReadOrErr(in any) ([]byte, error) -func ReadExistFile(filePath string) []byte -func TextScanner(in any) *scanner.Scanner -func LineScanner(in any) *bufio.Scanner +func NewIOReader(in any) (r io.Reader, err error) +func DiscardReader(src io.Reader) +func ReadFile(filePath string) []byte +func MustReadFile(filePath string) []byte +func ReadReader(r io.Reader) []byte +func MustReadReader(r io.Reader) []byte +func ReadString(in any) string +func ReadStringOrErr(in any) (string, error) +func ReadAll(in any) []byte +func GetContents(in any) []byte +func MustRead(in any) []byte +func ReadOrErr(in any) ([]byte, error) +func ReadExistFile(filePath string) []byte +func TextScanner(in any) *scanner.Scanner +func LineScanner(in any) *bufio.Scanner // source at fsutil/opwrite.go -func PutContents(filePath string, data any, fileFlag ...int) (int, error) -func WriteFile(filePath string, data any, perm os.FileMode, fileFlag ...int) error -func WriteOSFile(f *os.File, data any) (n int, err error) -func CopyFile(srcPath, dstPath string) error -func MustCopyFile(srcPath, dstPath string) +func OSTempFile(pattern string) (*os.File, error) +func TempFile(dir, pattern string) (*os.File, error) +func OSTempDir(pattern string) (string, error) +func TempDir(dir, pattern string) (string, error) +func MustSave(filePath string, data any, optFns ...OpenOptionFunc) +func SaveFile(filePath string, data any, optFns ...OpenOptionFunc) error +func PutContents(filePath string, data any, fileFlag ...int) (int, error) +func WriteFile(filePath string, data any, perm os.FileMode, fileFlag ...int) error +func WriteOSFile(f *os.File, data any) (n int, err error) +func CopyFile(srcPath, dstPath string) error +func MustCopyFile(srcPath, dstPath string) +func UpdateContents(filePath string, handleFn func(bs []byte) []byte) error ``` #### FsUtil Usage @@ -778,27 +820,54 @@ func main() { ``` +### Go Info + +> Package `github.com/gookit/goutil/goinfo` + +```go +// source at goinfo/gofunc.go +func FuncName(fn any) string +func CutFuncName(fullFcName string) (pkgPath, shortFnName string) +func PkgName(fullFcName string) string +func GoodFuncName(name string) bool +// source at goinfo/goinfo.go +func GoVersion() string +func ParseGoVersion(line string) (*GoInfo, error) +func OsGoInfo() (*GoInfo, error) +// source at goinfo/stack.go +func GetCallStacks(all bool) []byte +func GetCallerInfo(skip int) string +func SimpleCallersInfo(skip, num int) []string +func GetCallersInfo(skip, max int) []string +``` + ### JSON Utils > Package `github.com/gookit/goutil/jsonutil` ```go +// source at jsonutil/encoding.go +func MustString(v any) string +func Encode(v any) ([]byte, error) +func EncodePretty(v any) ([]byte, error) +func EncodeString(v any) (string, error) +func EncodeToWriter(v any, w io.Writer) error +func EncodeUnescapeHTML(v any) ([]byte, error) +func Decode(bts []byte, ptr any) error +func DecodeString(str string, ptr any) error +func DecodeReader(r io.Reader, ptr any) error // source at jsonutil/jsonutil.go -func WriteFile(filePath string, data any) error -func WritePretty(filePath string, data any) error -func ReadFile(filePath string, v any) error -func Pretty(v any) (string, error) -func Encode(v any) ([]byte, error) -func EncodePretty(v any) ([]byte, error) -func EncodeToWriter(v any, w io.Writer) error -func EncodeUnescapeHTML(v any) ([]byte, error) -func Decode(bts []byte, ptr any) error -func DecodeString(str string, ptr any) error -func DecodeReader(r io.Reader, ptr any) error -func Mapping(src, dst any) error -func IsJSON(s string) bool -func IsJSONFast(s string) bool -func StripComments(src string) string +func WriteFile(filePath string, data any) error +func WritePretty(filePath string, data any) error +func ReadFile(filePath string, v any) error +func Pretty(v any) (string, error) +func MustPretty(v any) string +func Mapping(src, dst any) error +func IsJSON(s string) bool +func IsJSONFast(s string) bool +func IsArray(s string) bool +func IsObject(s string) bool +func StripComments(src string) string ``` ### Map @@ -807,43 +876,44 @@ func StripComments(src string) string ```go // source at maputil/check.go -func HasKey(mp, key any) (ok bool) -func HasOneKey(mp any, keys ...any) (ok bool, key any) -func HasAllKeys(mp any, keys ...any) (ok bool, noKey any) +func HasKey(mp, key any) (ok bool) +func HasOneKey(mp any, keys ...any) (ok bool, key any) +func HasAllKeys(mp any, keys ...any) (ok bool, noKey any) // source at maputil/convert.go -func KeyToLower(src map[string]string) map[string]string -func ToStringMap(src map[string]any) map[string]string -func CombineToSMap(keys, values []string) SMap -func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V -func ToAnyMap(mp any) map[string]any -func TryAnyMap(mp any) (map[string]any, error) -func HTTPQueryString(data map[string]any) string -func StringsMapToAnyMap(ssMp map[string][]string) map[string]any -func ToString(mp map[string]any) string -func ToString2(mp any) string -func FormatIndent(mp any, indent string) string -func Flatten(mp map[string]any) map[string]any -func FlatWithFunc(mp map[string]any, fn reflects.FlatFunc) +func KeyToLower(src map[string]string) map[string]string +func ToStringMap(src map[string]any) map[string]string +func CombineToSMap(keys, values []string) SMap +func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V +func ToAnyMap(mp any) map[string]any +func TryAnyMap(mp any) (map[string]any, error) +func HTTPQueryString(data map[string]any) string +func StringsMapToAnyMap(ssMp map[string][]string) map[string]any +func ToString(mp map[string]any) string +func ToString2(mp any) string +func FormatIndent(mp any, indent string) string +func Flatten(mp map[string]any) map[string]any +func FlatWithFunc(mp map[string]any, fn reflects.FlatFunc) // source at maputil/format.go -func NewFormatter(mp any) *MapFormatter +func NewFormatter(mp any) *MapFormatter // source at maputil/get.go -func DeepGet(mp map[string]any, path string) (val any) -func QuietGet(mp map[string]any, path string) (val any) -func GetByPath(path string, mp map[string]any) (val any, ok bool) -func GetByPathKeys(mp map[string]any, keys []string) (val any, ok bool) -func Keys(mp any) (keys []string) -func Values(mp any) (values []any) -func EachAnyMap(mp any, fn func(key string, val any)) +func DeepGet(mp map[string]any, path string) (val any) +func QuietGet(mp map[string]any, path string) (val any) +func GetFromAny(path string, data any) (val any, ok bool) +func GetByPath(path string, mp map[string]any) (val any, ok bool) +func GetByPathKeys(mp map[string]any, keys []string) (val any, ok bool) +func Keys(mp any) (keys []string) +func Values(mp any) (values []any) +func EachAnyMap(mp any, fn func(key string, val any)) // source at maputil/maputil.go -func SimpleMerge(src, dst map[string]any) map[string]any -func DeepMerge(src, dst map[string]any, deep int) map[string]any -func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string -func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string -func MakeByPath(path string, val any) (mp map[string]any) -func MakeByKeys(keys []string, val any) (mp map[string]any) +func SimpleMerge(src, dst map[string]any) map[string]any +func DeepMerge(src, dst map[string]any, deep int) map[string]any +func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string +func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string +func MakeByPath(path string, val any) (mp map[string]any) +func MakeByKeys(keys []string, val any) (mp map[string]any) // source at maputil/setval.go -func SetByPath(mp *map[string]any, path string, val any) error -func SetByKeys(mp *map[string]any, keys []string, val any) (err error) +func SetByPath(mp *map[string]any, path string, val any) error +func SetByKeys(mp *map[string]any, keys []string, val any) (err error) ``` ### Math/Number @@ -852,68 +922,94 @@ func SetByKeys(mp *map[string]any, keys []string, val any) (err error) ```go // source at mathutil/check.go -func Compare(srcVal, dstVal any, op string) (ok bool) -func CompInt[T comdef.Xint](srcVal, dstVal T, op string) (ok bool) -func CompInt64(srcVal, dstVal int64, op string) bool -func CompFloat[T comdef.Float](srcVal, dstVal T, op string) (ok bool) -func CompValue[T comdef.XintOrFloat](srcVal, dstVal T, op string) (ok bool) -func InRange[T comdef.IntOrFloat](val, min, max T) bool -func OutRange[T comdef.IntOrFloat](val, min, max T) bool -func InUintRange[T comdef.Uint](val, min, max T) bool +func IsNumeric(c byte) bool +func Compare(first, second any, op string) bool +func CompInt[T comdef.Xint](first, second T, op string) (ok bool) +func CompInt64(first, second int64, op string) bool +func CompFloat[T comdef.Float](first, second T, op string) (ok bool) +func CompValue[T comdef.XintOrFloat](first, second T, op string) (ok bool) +func InRange[T comdef.IntOrFloat](val, min, max T) bool +func OutRange[T comdef.IntOrFloat](val, min, max T) bool +func InUintRange[T comdef.Uint](val, min, max T) bool +// source at mathutil/compare.go +func Min[T comdef.XintOrFloat](x, y T) T +func Max[T comdef.XintOrFloat](x, y T) T +func SwapMin[T comdef.XintOrFloat](x, y T) (T, T) +func SwapMax[T comdef.XintOrFloat](x, y T) (T, T) +func MaxInt(x, y int) int +func SwapMaxInt(x, y int) (int, int) +func MaxI64(x, y int64) int64 +func SwapMaxI64(x, y int64) (int64, int64) +func MaxFloat(x, y float64) float64 // source at mathutil/convert.go -func Int(in any) (int, error) -func QuietInt(in any) int -func MustInt(in any) int -func IntOrPanic(in any) int -func IntOrErr(in any) (iVal int, err error) -func ToInt(in any) (iVal int, err error) -func StrInt(s string) int -func Uint(in any) (uint64, error) -func QuietUint(in any) uint64 -func MustUint(in any) uint64 -func UintOrErr(in any) (uint64, error) -func ToUint(in any) (u64 uint64, err error) -func Int64(in any) (int64, error) -func SafeInt64(in any) int64 -func QuietInt64(in any) int64 -func MustInt64(in any) int64 -func Int64OrErr(in any) (int64, error) -func ToInt64(in any) (i64 int64, err error) -func QuietFloat(in any) float64 -func FloatOrPanic(in any) float64 -func MustFloat(in any) float64 -func Float(in any) (float64, error) -func FloatOrErr(in any) (float64, error) -func ToFloat(in any) (f64 float64, err error) -func StringOrPanic(val any) string -func MustString(val any) string -func ToString(val any) (string, error) -func StringOrErr(val any) (string, error) -func QuietString(val any) string -func String(val any) string -func TryToString(val any, defaultAsErr bool) (str string, err error) +func Int(in any) (int, error) +func SafeInt(in any) int +func QuietInt(in any) int +func MustInt(in any) int +func IntOrPanic(in any) int +func IntOrDefault(in any, defVal int) int +func IntOr(in any, defVal int) int +func IntOrErr(in any) (iVal int, err error) +func ToInt(in any) (iVal int, err error) +func ToIntWithFunc(in any, usrFn ToIntFunc) (iVal int, err error) +func StrInt(s string) int +func StrIntOr(s string, defVal int) int +func Uint(in any) (uint64, error) +func SafeUint(in any) uint64 +func QuietUint(in any) uint64 +func MustUint(in any) uint64 +func UintOrDefault(in any, defVal uint64) uint64 +func UintOr(in any, defVal uint64) uint64 +func UintOrErr(in any) (uint64, error) +func ToUint(in any) (u64 uint64, err error) +func ToUintWithFunc(in any, usrFn ToUintFunc) (u64 uint64, err error) +func Int64(in any) (int64, error) +func SafeInt64(in any) int64 +func QuietInt64(in any) int64 +func MustInt64(in any) int64 +func Int64OrDefault(in any, defVal int64) int64 +func Int64Or(in any, defVal int64) int64 +func Int64OrErr(in any) (int64, error) +func ToInt64(in any) (i64 int64, err error) +func ToInt64WithFunc(in any, usrFn ToInt64Func) (i64 int64, err error) +func QuietFloat(in any) float64 +func SafeFloat(in any) float64 +func FloatOrPanic(in any) float64 +func MustFloat(in any) float64 +func FloatOrDefault(in any, defVal float64) float64 +func FloatOr(in any, defVal float64) float64 +func Float(in any) (float64, error) +func FloatOrErr(in any) (float64, error) +func ToFloat(in any) (f64 float64, err error) +func ToFloatWithFunc(in any, usrFn ToFloatFunc) (f64 float64, err error) +func MustString(val any) string +func StringOrPanic(val any) string +func StringOrDefault(val any, defVal string) string +func StringOr(val any, defVal string) string +func ToString(val any) (string, error) +func StringOrErr(val any) (string, error) +func QuietString(val any) string +func String(val any) string +func SafeString(val any) string +func TryToString(val any, defaultAsErr bool) (str string, err error) +func ToStringWithFunc(val any, usrFn comdef.ToStringFunc) (str string, err error) +func Percent(val, total int) float64 +func ElapsedTime(startTime time.Time) string +// source at mathutil/format.go +func DataSize(size uint64) string +func HowLongAgo(sec int64) string // source at mathutil/mathutil.go -func Min[T comdef.XintOrFloat](x, y T) T -func Max[T comdef.XintOrFloat](x, y T) T -func SwapMin[T comdef.XintOrFloat](x, y T) (T, T) -func SwapMax[T comdef.XintOrFloat](x, y T) (T, T) -func MaxInt(x, y int) int -func SwapMaxInt(x, y int) (int, int) -func MaxI64(x, y int64) int64 -func SwapMaxI64(x, y int64) (int64, int64) -func MaxFloat(x, y float64) float64 -func OrElse[T comdef.XintOrFloat](in, nv T) T -// source at mathutil/number.go -func IsNumeric(c byte) bool -func Percent(val, total int) float64 -func ElapsedTime(startTime time.Time) string -func DataSize(size uint64) string -func HowLongAgo(sec int64) string +func OrElse[T comdef.XintOrFloat](val, defVal T) T +func ZeroOr[T comdef.XintOrFloat](val, defVal T) T +func LessOr[T comdef.XintOrFloat](val, max, devVal T) T +func LteOr[T comdef.XintOrFloat](val, max, devVal T) T +func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T +func GteOr[T comdef.XintOrFloat](val, min, defVal T) T // source at mathutil/random.go -func RandomInt(min, max int) int -func RandInt(min, max int) int -func RandIntWithSeed(min, max int, seed int64) int -func RandomIntWithSeed(min, max int, seed int64) int +func RandomInt(min, max int) int +func RandInt(min, max int) int +func RandIntWithSeed(min, max int, seed int64) int +func RandomIntWithSeed(min, max int, seed int64) int ``` ### Reflects @@ -922,45 +1018,63 @@ func RandomIntWithSeed(min, max int, seed int64) int ```go // source at reflects/check.go -func HasChild(v reflect.Value) bool -func IsArrayOrSlice(k reflect.Kind) bool -func IsSimpleKind(k reflect.Kind) bool -func IsAnyInt(k reflect.Kind) bool -func IsIntx(k reflect.Kind) bool -func IsUintX(k reflect.Kind) bool -func IsNil(v reflect.Value) bool -func IsFunc(val any) bool -func IsEqual(src, dst any) bool -func IsEmpty(v reflect.Value) bool -func IsEmptyValue(v reflect.Value) bool +func HasChild(v reflect.Value) bool +func IsArrayOrSlice(k reflect.Kind) bool +func IsSimpleKind(k reflect.Kind) bool +func IsAnyInt(k reflect.Kind) bool +func IsIntLike(k reflect.Kind) bool +func IsIntx(k reflect.Kind) bool +func IsUintX(k reflect.Kind) bool +func IsNil(v reflect.Value) bool +func CanBeNil(typ reflect.Type) bool +func IsFunc(val any) bool +func IsEqual(src, dst any) bool +func IsEmpty(v reflect.Value) bool +func IsEmptyReal(v reflect.Value) bool // source at reflects/conv.go -func BaseTypeVal(v reflect.Value) (value any, err error) -func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error) -func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) -func ConvSlice(oldSlRv reflect.Value, newElemTyp reflect.Type) (rv reflect.Value, err error) -func String(rv reflect.Value) string -func ToString(rv reflect.Value) (str string, err error) -func ValToString(rv reflect.Value, defaultAsErr bool) (str string, err error) +func BaseTypeVal(v reflect.Value) (value any, err error) +func ToBaseVal(v reflect.Value) (value any, err error) +func ConvToType(val any, typ reflect.Type) (rv reflect.Value, err error) +func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error) +func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) +func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error) +func ConvSlice(oldSlRv reflect.Value, newElemTyp reflect.Type) (rv reflect.Value, err error) +func String(rv reflect.Value) string +func ToString(rv reflect.Value) (str string, err error) +func ValToString(rv reflect.Value, defaultAsErr bool) (str string, err error) +// source at reflects/func.go +func NewFunc(fn any) *FuncX +func Call2(fn reflect.Value, args []reflect.Value) (reflect.Value, error) +func Call(fn reflect.Value, args []reflect.Value, opt *CallOpt) ([]reflect.Value, error) +func SafeCall2(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) +func SafeCall(fun reflect.Value, args []reflect.Value) (ret []reflect.Value, err error) +// source at reflects/map.go +func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) +func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) +func FlatMap(rv reflect.Value, fn FlatFunc) +// source at reflects/slice.go +func MakeSliceByElem(elTyp reflect.Type, len, cap int) reflect.Value +func FlatSlice(sl reflect.Value, depth int) reflect.Value // source at reflects/type.go -func ToBaseKind(kind reflect.Kind) BKind -func ToBKind(kind reflect.Kind) BKind -func TypeOf(v any) Type +func ToBaseKind(kind reflect.Kind) BKind +func ToBKind(kind reflect.Kind) BKind +func TypeOf(v any) Type // source at reflects/util.go -func Elem(v reflect.Value) reflect.Value -func Indirect(v reflect.Value) reflect.Value -func Len(v reflect.Value) int -func SliceSubKind(typ reflect.Type) reflect.Kind -func SliceElemKind(typ reflect.Type) reflect.Kind -func UnexportedValue(rv reflect.Value) any -func SetUnexportedValue(rv reflect.Value, value any) -func SetValue(rv reflect.Value, val any) error -func SetRValue(rv, val reflect.Value) -func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) -func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) -func FlatMap(rv reflect.Value, fn FlatFunc) +func Elem(v reflect.Value) reflect.Value +func Indirect(v reflect.Value) reflect.Value +func UnwrapAny(v reflect.Value) reflect.Value +func TypeReal(t reflect.Type) reflect.Type +func TypeElem(t reflect.Type) reflect.Type +func Len(v reflect.Value) int +func SliceSubKind(typ reflect.Type) reflect.Kind +func SliceElemKind(typ reflect.Type) reflect.Kind +func UnexportedValue(rv reflect.Value) any +func SetUnexportedValue(rv reflect.Value, value any) +func SetValue(rv reflect.Value, val any) error +func SetRValue(rv, val reflect.Value) // source at reflects/value.go -func Wrap(rv reflect.Value) Value -func ValueOf(v any) Value +func Wrap(rv reflect.Value) Value +func ValueOf(v any) Value ``` ### Stdio @@ -969,65 +1083,24 @@ func ValueOf(v any) Value ```go // source at stdio/ioutil.go -func QuietFprint(w io.Writer, a ...any) -func QuietFprintf(w io.Writer, tpl string, vs ...any) -func QuietFprintln(w io.Writer, a ...any) -func QuietWriteString(w io.Writer, ss ...string) +func QuietFprint(w io.Writer, a ...any) +func QuietFprintf(w io.Writer, tpl string, vs ...any) +func QuietFprintln(w io.Writer, a ...any) +func QuietWriteString(w io.Writer, ss ...string) // source at stdio/stdio.go -func DiscardReader(src io.Reader) -func ReadString(r io.Reader) string -func MustReadReader(r io.Reader) []byte -func NewIOReader(in any) io.Reader -func NewScanner(in any) *bufio.Scanner -func WriteByte(b byte) -func WriteBytes(bs []byte) -func WritelnBytes(bs []byte) -func WriteString(s string) -func Writeln(s string) +func DiscardReader(src io.Reader) +func ReadString(r io.Reader) string +func MustReadReader(r io.Reader) []byte +func NewIOReader(in any) io.Reader +func NewScanner(in any) *bufio.Scanner +func WriteByte(b byte) +func WriteBytes(bs []byte) +func WritelnBytes(bs []byte) +func WriteString(s string) +func Writeln(s string) // source at stdio/writer.go -func NewWriteWrapper(w io.Writer) *WriteWrapper -``` - -### Standard - -> Package `github.com/gookit/goutil/stdutil` - -```go -// source at stdutil/chan.go -func WaitCloseSignals(closer io.Closer) error -func Go(f func() error) error -func SignalHandler(ctx context.Context, signals ...os.Signal) (execute func() error, interrupt func(error)) -// source at stdutil/check.go -func IsNil(v any) bool -func IsEmpty(v any) bool -func IsFunc(val any) bool -func IsEqual(src, dst any) bool -func Contains(data, elem any) bool -func IsContains(data, elem any) bool -func CheckContains(data, elem any) (valid, found bool) -func ValueIsEmpty(v reflect.Value) bool -func ValueLen(v reflect.Value) int -// source at stdutil/conv.go -func ToString(v any) string -func MustString(v any) string -func TryString(v any) (string, error) -func BaseTypeVal(val any) (value any, err error) -func BaseTypeVal2(v reflect.Value) (value any, err error) -// source at stdutil/gofunc.go -func FuncName(fn any) string -func CutFuncName(fullFcName string) (pkgPath, shortFnName string) -func PkgName(fullFcName string) string -// source at stdutil/stack.go -func GetCallStacks(all bool) []byte -func GetCallerInfo(skip int) string -func SimpleCallersInfo(skip, num int) []string -func GetCallersInfo(skip, max int) []string -// source at stdutil/stdutil.go -func DiscardE(_ error) -func PanicIfErr(err error) -func PanicIf(err error) -func Panicf(format string, v ...any) -func GoVersion() string +func WrapW(w io.Writer) *WriteWrapper +func NewWriteWrapper(w io.Writer) *WriteWrapper ``` ### Structs @@ -1036,49 +1109,49 @@ func GoVersion() string ```go // source at structs/alias.go -func NewAliases(checker func(alias string)) *Aliases +func NewAliases(checker func(alias string)) *Aliases // source at structs/convert.go -func ToMap(st any, optFns ...MapOptFunc) map[string]any -func MustToMap(st any, optFns ...MapOptFunc) map[string]any -func TryToMap(st any, optFns ...MapOptFunc) (map[string]any, error) -func ToSMap(st any, optFns ...MapOptFunc) map[string]string -func TryToSMap(st any, optFns ...MapOptFunc) (map[string]string, error) -func MustToSMap(st any, optFns ...MapOptFunc) map[string]string -func ToString(st any, optFns ...MapOptFunc) string -func WithMapTagName(tagName string) MapOptFunc -func MergeAnonymous(opt *MapOptions) -func ExportPrivate(opt *MapOptions) -func StructToMap(st any, optFns ...MapOptFunc) (map[string]any, error) +func ToMap(st any, optFns ...MapOptFunc) map[string]any +func MustToMap(st any, optFns ...MapOptFunc) map[string]any +func TryToMap(st any, optFns ...MapOptFunc) (map[string]any, error) +func ToSMap(st any, optFns ...MapOptFunc) map[string]string +func TryToSMap(st any, optFns ...MapOptFunc) (map[string]string, error) +func MustToSMap(st any, optFns ...MapOptFunc) map[string]string +func ToString(st any, optFns ...MapOptFunc) string +func WithMapTagName(tagName string) MapOptFunc +func MergeAnonymous(opt *MapOptions) +func ExportPrivate(opt *MapOptions) +func StructToMap(st any, optFns ...MapOptFunc) (map[string]any, error) // source at structs/copy.go -func MapStruct(srcSt, dstSt any) +func MapStruct(srcSt, dstSt any) // source at structs/data.go -func NewLiteData(data map[string]any) *Data -func NewData() *Data -func NewOrderedMap(len int) *OrderedMap +func NewLiteData(data map[string]any) *Data +func NewData() *Data +func NewOrderedData(cap int) *OrderedData // source at structs/init.go -func Init(ptr any, optFns ...InitOptFunc) error -func InitDefaults(ptr any, optFns ...InitOptFunc) error +func Init(ptr any, optFns ...InitOptFunc) error +func InitDefaults(ptr any, optFns ...InitOptFunc) error // source at structs/structs.go -func IsExported(name string) bool -func IsUnexported(name string) bool +func IsExported(name string) bool +func IsUnexported(name string) bool // source at structs/tags.go -func ParseTags(st any, tagNames []string) (map[string]maputil.SMap, error) -func ParseReflectTags(rt reflect.Type, tagNames []string) (map[string]maputil.SMap, error) -func NewTagParser(tagNames ...string) *TagParser -func ParseTagValueDefault(field, tagVal string) (mp maputil.SMap, err error) -func ParseTagValueQuick(tagVal string, defines []string) maputil.SMap -func ParseTagValueDefine(sep string, defines []string) TagValFunc -func ParseTagValueNamed(field, tagVal string, keys ...string) (mp maputil.SMap, err error) +func ParseTags(st any, tagNames []string) (map[string]maputil.SMap, error) +func ParseReflectTags(rt reflect.Type, tagNames []string) (map[string]maputil.SMap, error) +func NewTagParser(tagNames ...string) *TagParser +func ParseTagValueDefault(field, tagVal string) (mp maputil.SMap, err error) +func ParseTagValueQuick(tagVal string, defines []string) maputil.SMap +func ParseTagValueDefine(sep string, defines []string) TagValFunc +func ParseTagValueNamed(field, tagVal string, keys ...string) (mp maputil.SMap, err error) // source at structs/value.go -func NewValue(val any) *Value +func NewValue(val any) *Value // source at structs/wrapper.go -func Wrap(src any) *Wrapper -func NewWrapper(src any) *Wrapper -func WrapValue(rv reflect.Value) *Wrapper +func Wrap(src any) *Wrapper +func NewWrapper(src any) *Wrapper +func WrapValue(rv reflect.Value) *Wrapper // source at structs/writer.go -func NewWriter(ptr any) *Wrapper -func WithParseDefault(opt *SetOptions) -func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error +func NewWriter(ptr any) *Wrapper +func WithParseDefault(opt *SetOptions) +func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error ``` ### Strings @@ -1087,219 +1160,267 @@ func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error ```go // source at strutil/bytes.go -func NewBuffer() *Buffer -func NewByteChanPool(maxSize, width, capWidth int) *ByteChanPool +func NewBuffer() *Buffer +func NewByteChanPool(maxSize, width, capWidth int) *ByteChanPool // source at strutil/check.go -func IsNumChar(c byte) bool -func IsNumeric(s string) bool -func IsAlphabet(char uint8) bool -func IsAlphaNum(c uint8) bool -func StrPos(s, sub string) int -func BytePos(s string, bt byte) int -func IEqual(s1, s2 string) bool -func NoCaseEq(s, t string) bool -func IContains(s, sub string) bool -func ContainsByte(s string, c byte) bool -func ContainsOne(s string, subs []string) bool -func HasOneSub(s string, subs []string) bool -func ContainsAll(s string, subs []string) bool -func HasAllSubs(s string, subs []string) bool -func IsStartsOf(s string, prefixes []string) bool -func HasOnePrefix(s string, prefixes []string) bool -func HasPrefix(s string, prefix string) bool -func IsStartOf(s, prefix string) bool -func HasSuffix(s string, suffix string) bool -func IsEndOf(s, suffix string) bool -func HasOneSuffix(s string, suffixes []string) bool -func IsValidUtf8(s string) bool -func IsSpace(c byte) bool -func IsEmpty(s string) bool -func IsBlank(s string) bool -func IsNotBlank(s string) bool -func IsBlankBytes(bs []byte) bool -func IsSymbol(r rune) bool -func HasEmpty(ss ...string) bool -func IsAllEmpty(ss ...string) bool -func IsVersion(s string) bool -func Compare(s1, s2, op string) bool -func VersionCompare(v1, v2, op string) bool -func SimpleMatch(s string, keywords []string) bool -func QuickMatch(pattern, s string) bool -func PathMatch(pattern, s string) bool -func GlobMatch(pattern, s string) bool -func LikeMatch(pattern, s string) bool -func MatchNodePath(pattern, s string, sep string) bool +func IsNumChar(c byte) bool +func IsNumeric(s string) bool +func IsAlphabet(char uint8) bool +func IsAlphaNum(c uint8) bool +func StrPos(s, sub string) int +func BytePos(s string, bt byte) int +func IEqual(s1, s2 string) bool +func NoCaseEq(s, t string) bool +func IContains(s, sub string) bool +func ContainsByte(s string, c byte) bool +func ContainsOne(s string, subs []string) bool +func HasOneSub(s string, subs []string) bool +func ContainsAll(s string, subs []string) bool +func HasAllSubs(s string, subs []string) bool +func IsStartsOf(s string, prefixes []string) bool +func HasOnePrefix(s string, prefixes []string) bool +func HasPrefix(s string, prefix string) bool +func IsStartOf(s, prefix string) bool +func HasSuffix(s string, suffix string) bool +func IsEndOf(s, suffix string) bool +func HasOneSuffix(s string, suffixes []string) bool +func IsValidUtf8(s string) bool +func IsSpace(c byte) bool +func IsEmpty(s string) bool +func IsBlank(s string) bool +func IsNotBlank(s string) bool +func IsBlankBytes(bs []byte) bool +func IsSymbol(r rune) bool +func HasEmpty(ss ...string) bool +func IsAllEmpty(ss ...string) bool +func IsVersion(s string) bool +func Compare(s1, s2, op string) bool +func VersionCompare(v1, v2, op string) bool +func SimpleMatch(s string, keywords []string) bool +func QuickMatch(pattern, s string) bool +func PathMatch(pattern, s string) bool +func GlobMatch(pattern, s string) bool +func LikeMatch(pattern, s string) bool +func MatchNodePath(pattern, s string, sep string) bool +// source at strutil/convbase.go +func Base10Conv(src string, to int) string +func BaseConv(src string, from, to int) string +func BaseConvByTpl(src string, fromBase, toBase string) string // source at strutil/convert.go -func Quote(s string) string -func Unquote(s string) string -func Join(sep string, ss ...string) string -func JoinList(sep string, ss []string) string -func JoinAny(sep string, parts ...any) string -func Implode(sep string, ss ...string) string -func String(val any) (string, error) -func ToString(val any) (string, error) -func QuietString(in any) string -func SafeString(in any) string -func MustString(in any) string -func StringOrErr(val any) (string, error) -func AnyToString(val any, defaultAsErr bool) (str string, err error) -func Byte2str(b []byte) string -func Byte2string(b []byte) string -func ToBytes(s string) (b []byte) -func ToBool(s string) (bool, error) -func QuietBool(s string) bool -func MustBool(s string) bool -func Bool(s string) (bool, error) -func Int(s string) (int, error) -func ToInt(s string) (int, error) -func Int2(s string) int -func QuietInt(s string) int -func MustInt(s string) int -func IntOrPanic(s string) int -func Int64(s string) int64 -func QuietInt64(s string) int64 -func ToInt64(s string) (int64, error) -func Int64OrErr(s string) (int64, error) -func MustInt64(s string) int64 -func Int64OrPanic(s string) int64 -func Ints(s string, sep ...string) []int -func ToInts(s string, sep ...string) ([]int, error) -func ToIntSlice(s string, sep ...string) (ints []int, err error) -func ToArray(s string, sep ...string) []string -func Strings(s string, sep ...string) []string -func ToStrings(s string, sep ...string) []string -func ToSlice(s string, sep ...string) []string -func ToOSArgs(s string) []string -func ToDuration(s string) (time.Duration, error) -// source at strutil/crypto.go -func Md5(src any) string -func MD5(src any) string -func GenMd5(src any) string -func Md5Bytes(src any) []byte -func HashPasswd(pwd, key string) string -func VerifyPasswd(pwdMAC, pwd, key string) bool +func Quote(s string) string +func Unquote(s string) string +func Join(sep string, ss ...string) string +func JoinList(sep string, ss []string) string +func JoinAny(sep string, parts ...any) string +func Implode(sep string, ss ...string) string +func String(val any) (string, error) +func ToString(val any) (string, error) +func StringOrErr(val any) (string, error) +func QuietString(val any) string +func SafeString(in any) string +func StringOrPanic(val any) string +func MustString(val any) string +func StringOrDefault(val any, defVal string) string +func StringOr(val any, defVal string) string +func AnyToString(val any, defaultAsErr bool) (s string, err error) +func ToStringWithFunc(val any, fbFn comdef.ToStringFunc) (str string, err error) +func ToBool(s string) (bool, error) +func QuietBool(s string) bool +func SafeBool(s string) bool +func MustBool(s string) bool +func Bool(s string) (bool, error) +func Int(s string) (int, error) +func ToInt(s string) (int, error) +func IntOrDefault(s string, defVal int) int +func IntOr(s string, defVal int) int +func SafeInt(s string) int +func QuietInt(s string) int +func MustInt(s string) int +func IntOrPanic(s string) int +func Int64(s string) int64 +func SafeInt64(s string) int64 +func QuietInt64(s string) int64 +func ToInt64(s string) (int64, error) +func Int64OrDefault(s string, defVal int64) int64 +func Int64Or(s string, defVal int64) int64 +func Int64OrErr(s string) (int64, error) +func MustInt64(s string) int64 +func Int64OrPanic(s string) int64 +func Uint(s string) uint64 +func SafeUint(s string) uint64 +func ToUint(s string) (uint64, error) +func UintOrErr(s string) (uint64, error) +func MustUint(s string) uint64 +func UintOrPanic(s string) uint64 +func UintOrDefault(s string, defVal uint64) uint64 +func UintOr(s string, defVal uint64) uint64 +func Byte2str(b []byte) string +func Byte2string(b []byte) string +func ToBytes(s string) (b []byte) +func Ints(s string, sep ...string) []int +func ToInts(s string, sep ...string) ([]int, error) +func ToIntSlice(s string, sep ...string) (ints []int, err error) +func ToArray(s string, sep ...string) []string +func Strings(s string, sep ...string) []string +func ToStrings(s string, sep ...string) []string +func ToSlice(s string, sep ...string) []string +func ToOSArgs(s string) []string +func ToDuration(s string) (time.Duration, error) // source at strutil/encode.go -func EscapeJS(s string) string -func EscapeHTML(s string) string -func AddSlashes(s string) string -func StripSlashes(s string) string -func URLEncode(s string) string -func URLDecode(s string) string -func B32Encode(str string) string -func B32Decode(str string) string -func B64Encode(str string) string -func B64EncodeBytes(src []byte) []byte -func B64Decode(str string) string -func B64DecodeBytes(str string) []byte -func Encoding(base int, typ BaseType) BaseEncoder +func EscapeJS(s string) string +func EscapeHTML(s string) string +func AddSlashes(s string) string +func StripSlashes(s string) string +func URLEncode(s string) string +func URLDecode(s string) string +func B32Encode(str string) string +func B32Decode(str string) string +func B64Encode(str string) string +func B64EncodeBytes(src []byte) []byte +func B64Decode(str string) string +func B64DecodeBytes(str []byte) []byte // source at strutil/ext.go -func NewComparator(src, dst string) *SimilarComparator -func Similarity(s, t string, rate float32) (float32, bool) +func NewComparator(src, dst string) *SimilarComparator +func Similarity(s, t string, rate float32) (float32, bool) // source at strutil/filter.go -func Trim(s string, cutSet ...string) string -func Ltrim(s string, cutSet ...string) string -func LTrim(s string, cutSet ...string) string -func TrimLeft(s string, cutSet ...string) string -func Rtrim(s string, cutSet ...string) string -func RTrim(s string, cutSet ...string) string -func TrimRight(s string, cutSet ...string) string -func FilterEmail(s string) string -func Filter(ss []string, fls ...comdef.StringMatchFunc) []string +func Trim(s string, cutSet ...string) string +func Ltrim(s string, cutSet ...string) string +func LTrim(s string, cutSet ...string) string +func TrimLeft(s string, cutSet ...string) string +func Rtrim(s string, cutSet ...string) string +func RTrim(s string, cutSet ...string) string +func TrimRight(s string, cutSet ...string) string +func FilterEmail(s string) string +func Filter(ss []string, fls ...comdef.StringMatchFunc) []string // source at strutil/format.go -func Title(s string) string -func Lower(s string) string -func Lowercase(s string) string -func Upper(s string) string -func Uppercase(s string) string -func UpperWord(s string) string -func LowerFirst(s string) string -func UpperFirst(s string) string -func SnakeCase(s string, sep ...string) string -func Camel(s string, sep ...string) string -func CamelCase(s string, sep ...string) string -func Indent(s, prefix string) string -func IndentBytes(b, prefix []byte) []byte -// source at strutil/id.go -func MicroTimeID() string -func MicroTimeHexID() string -func DatetimeNo(prefix string) string +func Title(s string) string +func Lower(s string) string +func Lowercase(s string) string +func Upper(s string) string +func Uppercase(s string) string +func UpperWord(s string) string +func LowerFirst(s string) string +func UpperFirst(s string) string +func SnakeCase(s string, sep ...string) string +func Camel(s string, sep ...string) string +func CamelCase(s string, sep ...string) string +func Indent(s, prefix string) string +func IndentBytes(b, prefix []byte) []byte +// source at strutil/gensn.go +func MicroTimeID() string +func MicroTimeHexID() string +func MTimeHexID() string +func MTimeBaseID(toBase int) string +func DatetimeNo(prefix string) string +func DateSN(prefix string) string +func DateSNV2(prefix string, extBase ...int) string +// source at strutil/hash.go +func Md5(src any) string +func MD5(src any) string +func GenMd5(src any) string +func Md5Bytes(src any) []byte +func ShortMd5(src any) string +func HashPasswd(pwd, key string) string +func VerifyPasswd(pwdMAC, pwd, key string) bool // source at strutil/padding.go -func Padding(s, pad string, length int, pos PosFlag) string -func PadLeft(s, pad string, length int) string -func PadRight(s, pad string, length int) string -func Resize(s string, length int, align PosFlag) string -func PadChars[T byte | rune](cs []T, pad T, length int, pos PosFlag) []T -func PadBytes(bs []byte, pad byte, length int, pos PosFlag) []byte -func PadBytesLeft(bs []byte, pad byte, length int) []byte -func PadBytesRight(bs []byte, pad byte, length int) []byte -func PadRunes(rs []rune, pad rune, length int, pos PosFlag) []rune -func PadRunesLeft(rs []rune, pad rune, length int) []rune -func PadRunesRight(rs []rune, pad rune, length int) []rune -func Repeat(s string, times int) string -func RepeatRune(char rune, times int) []rune -func RepeatBytes(char byte, times int) []byte -func RepeatChars[T byte | rune](char T, times int) []T +func Padding(s, pad string, length int, pos PosFlag) string +func PadLeft(s, pad string, length int) string +func PadRight(s, pad string, length int) string +func Resize(s string, length int, align PosFlag) string +func PadChars[T byte | rune](cs []T, pad T, length int, pos PosFlag) []T +func PadBytes(bs []byte, pad byte, length int, pos PosFlag) []byte +func PadBytesLeft(bs []byte, pad byte, length int) []byte +func PadBytesRight(bs []byte, pad byte, length int) []byte +func PadRunes(rs []rune, pad rune, length int, pos PosFlag) []rune +func PadRunesLeft(rs []rune, pad rune, length int) []rune +func PadRunesRight(rs []rune, pad rune, length int) []rune +func Repeat(s string, times int) string +func RepeatRune(char rune, times int) []rune +func RepeatBytes(char byte, times int) []byte +func RepeatChars[T byte | rune](char T, times int) []T // source at strutil/parse.go -func MustToTime(s string, layouts ...string) time.Time -func ToTime(s string, layouts ...string) (t time.Time, err error) -func ParseSizeRange(expr string, opt *ParseSizeOpt) (min, max uint64, err error) -func SafeByteSize(sizeStr string) uint64 -func ToByteSize(sizeStr string) (uint64, error) +func MustToTime(s string, layouts ...string) time.Time +func ToTime(s string, layouts ...string) (t time.Time, err error) +func ParseSizeRange(expr string, opt *ParseSizeOpt) (min, max uint64, err error) +func SafeByteSize(sizeStr string) uint64 +func ToByteSize(sizeStr string) (uint64, error) // source at strutil/random.go -func RandomChars(ln int) string -func RandomCharsV2(ln int) string -func RandomCharsV3(ln int) string -func RandomBytes(length int) ([]byte, error) -func RandomString(length int) (string, error) -func RandWithTpl(n int, letters string) string +func RandomChars(ln int) string +func RandomCharsV2(ln int) string +func RandomCharsV3(ln int) string +func RandWithTpl(n int, letters string) string +func RandomString(length int) (string, error) +func RandomBytes(length int) ([]byte, error) // source at strutil/runes.go -func RuneIsWord(c rune) bool -func RuneIsLower(c rune) bool -func RuneIsUpper(c rune) bool -func RunePos(s string, ru rune) int -func IsSpaceRune(r rune) bool -func Utf8Len(s string) int -func Utf8len(s string) int -func RuneCount(s string) int -func RuneWidth(r rune) int -func TextWidth(s string) int -func Utf8Width(s string) int -func RunesWidth(rs []rune) (w int) -func Truncate(s string, w int, tail string) string -func TextTruncate(s string, w int, tail string) string -func Utf8Truncate(s string, w int, tail string) string -func TextSplit(s string, w int) []string -func Utf8Split(s string, w int) []string -func TextWrap(s string, w int) string -func WidthWrap(s string, w int) string -func WordWrap(s string, w int) string +func RuneIsWord(c rune) bool +func RuneIsLower(c rune) bool +func RuneIsUpper(c rune) bool +func RunePos(s string, ru rune) int +func IsSpaceRune(r rune) bool +func Utf8Len(s string) int +func Utf8len(s string) int +func RuneCount(s string) int +func RuneWidth(r rune) int +func TextWidth(s string) int +func Utf8Width(s string) int +func RunesWidth(rs []rune) (w int) +func Truncate(s string, w int, tail string) string +func TextTruncate(s string, w int, tail string) string +func Utf8Truncate(s string, w int, tail string) string +func TextSplit(s string, w int) []string +func Utf8Split(s string, w int) []string +func TextWrap(s string, w int) string +func WidthWrap(s string, w int) string +func WordWrap(s string, w int) string // source at strutil/split.go -func Cut(s, sep string) (before string, after string, found bool) -func QuietCut(s, sep string) (before string, after string) -func MustCut(s, sep string) (before string, after string) -func TrimCut(s, sep string) (string, string) -func SplitKV(s, sep string) (string, string) -func SplitValid(s, sep string) (ss []string) -func Split(s, sep string) (ss []string) -func SplitNValid(s, sep string, n int) (ss []string) -func SplitN(s, sep string, n int) (ss []string) -func SplitTrimmed(s, sep string) (ss []string) -func SplitNTrimmed(s, sep string, n int) (ss []string) -func Substr(s string, pos, length int) string -func SplitInlineComment(val string, strict ...bool) (string, string) -func FirstLine(output string) string +func BeforeFirst(s, sep string) string +func AfterFirst(s, sep string) string +func BeforeLast(s, sep string) string +func AfterLast(s, sep string) string +func Cut(s, sep string) (before string, after string, found bool) +func QuietCut(s, sep string) (before string, after string) +func MustCut(s, sep string) (before string, after string) +func TrimCut(s, sep string) (string, string) +func SplitKV(s, sep string) (string, string) +func SplitValid(s, sep string) (ss []string) +func Split(s, sep string) (ss []string) +func SplitNValid(s, sep string, n int) (ss []string) +func SplitN(s, sep string, n int) (ss []string) +func SplitTrimmed(s, sep string) (ss []string) +func SplitNTrimmed(s, sep string, n int) (ss []string) +func Substr(s string, pos, length int) string +func SplitInlineComment(val string, strict ...bool) (string, string) +func FirstLine(output string) string // source at strutil/strutil.go -func OrCond(cond bool, s1, s2 string) string -func OrElse(s, orVal string) string -func OrHandle(s string, fn func(s string) string) string -func Valid(ss ...string) string -func Replaces(str string, pairs map[string]string) string -func NewReplacer(pairs map[string]string) *strings.Replacer -func PrettyJSON(v any) (string, error) -func RenderTemplate(input string, data any, fns template.FuncMap, isFile ...bool) string -func RenderText(input string, data any, fns template.FuncMap, isFile ...bool) string -func WrapTag(s, tag string) string -func SubstrCount(s string, substr string, params ...uint64) (int, error) +func OrCond(cond bool, s1, s2 string) string +func BlankOr(val, defVal string) string +func ZeroOr[T ~string](val, defVal T) T +func ErrorOr(s string, err error, defVal string) string +func OrElse(s, orVal string) string +func OrHandle(s string, fn comdef.StringHandleFunc) string +func Valid(ss ...string) string +func Replaces(str string, pairs map[string]string) string +func NewReplacer(pairs map[string]string) *strings.Replacer +func PrettyJSON(v any) (string, error) +func RenderTemplate(input string, data any, fns template.FuncMap, isFile ...bool) string +func RenderText(input string, data any, fns template.FuncMap, isFile ...bool) string +func WrapTag(s, tag string) string +func SubstrCount(s, substr string, params ...uint64) (int, error) +``` + +### Syncs + +> Package `github.com/gookit/goutil/syncs` + +```go +// source at syncs/chan.go +func WaitCloseSignals(onClose func(sig os.Signal)) +func Go(f func() error) error +// source at syncs/group.go +func NewCtxErrGroup(ctx context.Context, limit ...int) (*ErrGroup, context.Context) +func NewErrGroup(limit ...int) *ErrGroup +// source at syncs/signal.go +func SignalHandler(ctx context.Context, signals ...os.Signal) (execute func() error, interrupt func(error)) ``` ### System Utils @@ -1308,68 +1429,69 @@ func SubstrCount(s string, substr string, params ...uint64) (int, error) ```go // source at sysutil/exec.go -func NewCmd(bin string, args ...string) *cmdr.Cmd -func FlushExec(bin string, args ...string) error -func QuickExec(cmdLine string, workDir ...string) (string, error) -func ExecLine(cmdLine string, workDir ...string) (string, error) -func ExecCmd(binName string, args []string, workDir ...string) (string, error) -func ShellExec(cmdLine string, shells ...string) (string, error) +func NewCmd(bin string, args ...string) *cmdr.Cmd +func FlushExec(bin string, args ...string) error +func QuickExec(cmdLine string, workDir ...string) (string, error) +func ExecLine(cmdLine string, workDir ...string) (string, error) +func ExecCmd(binName string, args []string, workDir ...string) (string, error) +func ShellExec(cmdLine string, shells ...string) (string, error) // source at sysutil/stack.go -func CallersInfos(skip, num int, filters ...func(file string, fc *runtime.Func) bool) []*CallerInfo +func CallersInfos(skip, num int, filters ...func(file string, fc *runtime.Func) bool) []*CallerInfo // source at sysutil/sysenv.go -func IsMSys() bool -func IsConsole(out io.Writer) bool -func IsTerminal(fd uintptr) bool -func StdIsTerminal() bool -func Hostname() string -func CurrentShell(onlyName bool) (path string) -func HasShellEnv(shell string) bool -func IsShellSpecialVar(c uint8) bool -func FindExecutable(binName string) (string, error) -func Executable(binName string) (string, error) -func HasExecutable(binName string) bool -func Getenv(name string, def ...string) string -func Environ() map[string]string -func EnvMapWith(newEnv map[string]string) map[string]string -func EnvPaths() []string -func SearchPath(keywords string, limit int) []string +func IsMSys() bool +func IsConsole(out io.Writer) bool +func IsTerminal(fd uintptr) bool +func StdIsTerminal() bool +func Hostname() string +func CurrentShell(onlyName bool) (path string) +func HasShellEnv(shell string) bool +func IsShellSpecialVar(c uint8) bool +func FindExecutable(binName string) (string, error) +func Executable(binName string) (string, error) +func HasExecutable(binName string) bool +func Getenv(name string, def ...string) string +func Environ() map[string]string +func EnvMapWith(newEnv map[string]string) map[string]string +func EnvPaths() []string +func SearchPath(keywords string, limit int) []string // source at sysutil/sysgo.go -func GoVersion() string -func ParseGoVersion(line string) (*GoInfo, error) -func OsGoInfo() (*GoInfo, error) +func GoVersion() string +func ParseGoVersion(line string) (*GoInfo, error) +func OsGoInfo() (*GoInfo, error) // source at sysutil/sysutil.go -func Workdir() string -func BinDir() string -func BinName() string -func BinFile() string -func Open(fileOrURL string) error -func OpenBrowser(fileOrURL string) error -func OpenFile(path string) error +func Workdir() string +func BinDir() string +func BinName() string +func BinFile() string +func Open(fileOrURL string) error +func OpenBrowser(fileOrURL string) error +func OpenFile(path string) error // source at sysutil/sysutil_nonwin.go -func Kill(pid int, signal syscall.Signal) error -func ProcessExists(pid int) bool +func Kill(pid int, signal syscall.Signal) error +func ProcessExists(pid int) bool // source at sysutil/sysutil_unix.go -func IsWin() bool -func IsWindows() bool -func IsMac() bool -func IsDarwin() bool -func IsLinux() bool -func OpenURL(URL string) error +func IsWin() bool +func IsWindows() bool +func IsMac() bool +func IsDarwin() bool +func IsLinux() bool +func OpenURL(URL string) error // source at sysutil/user.go -func MustFindUser(uname string) *user.User -func LoginUser() *user.User -func CurrentUser() *user.User -func UHomeDir() string -func UserHomeDir() string -func HomeDir() string -func UserDir(subPath string) string -func UserCacheDir(subPath string) string -func UserConfigDir(subPath string) string -func ExpandPath(path string) string -func ExpandHome(path string) string +func MustFindUser(uname string) *user.User +func LoginUser() *user.User +func CurrentUser() *user.User +func UHomeDir() string +func UserHomeDir() string +func HomeDir() string +func UserDir(subPath string) string +func UserCacheDir(subPath string) string +func UserConfigDir(subPath string) string +func ExpandPath(path string) string +func ExpandHome(path string) string // source at sysutil/user_nonwin.go -func ChangeUserByName(newUname string) (err error) -func ChangeUserUidGid(newUID int, newGid int) (err error) +func ChangeUserByName(newUname string) error +func ChangeUserUidGid(newUID int, newGid int) error +func ChangeUserUIDGid(newUID int, newGid int) (err error) ``` ### Testing Utils @@ -1378,34 +1500,37 @@ func ChangeUserUidGid(newUID int, newGid int) (err error) ```go // source at testutil/buffer.go -func NewBuffer() *byteutil.Buffer +func NewBuffer() *byteutil.Buffer // source at testutil/envmock.go -func MockEnvValue(key, val string, fn func(nv string)) -func MockEnvValues(kvMap map[string]string, fn func()) -func MockOsEnvByText(envText string, fn func()) -func MockOsEnv(mp map[string]string, fn func()) -func ClearOSEnv() -func RevertOSEnv() -func MockCleanOsEnv(mp map[string]string, fn func()) -// source at testutil/fsmock.go -func NewDirEnt(fpath string, isDir ...bool) *fakeobj.DirEntry +func MockEnvValue(key, val string, fn func(nv string)) +func MockEnvValues(kvMap map[string]string, fn func()) +func MockOsEnvByText(envText string, fn func()) +func MockOsEnv(mp map[string]string, fn func()) +func ClearOSEnv() +func RevertOSEnv() +func MockCleanOsEnv(mp map[string]string, fn func()) // source at testutil/httpmock.go -func NewHttpRequest(method, path string, data *MD) *http.Request -func MockRequest(h http.Handler, method, path string, data *MD) *httptest.ResponseRecorder -func TestMain(m *testing.M) -func NewEchoServer() *httptest.Server -func BuildEchoReply(r *http.Request) *EchoReply -func ParseRespToReply(w *http.Response) *EchoReply -func ParseBodyToReply(bd io.ReadCloser) *EchoReply +func NewHttpRequest(method, path string, data *MD) *http.Request +func NewHTTPRequest(method, path string, data *MD) *http.Request +func MockRequest(h http.Handler, method, path string, data *MD) *httptest.ResponseRecorder +func TestMain(m *testing.M) +func NewEchoServer() *httptest.Server +func BuildEchoReply(r *http.Request) *EchoReply +func ParseRespToReply(w *http.Response) *EchoReply +func ParseBodyToReply(bd io.ReadCloser) *EchoReply // source at testutil/testutil.go -func DiscardStdout() error -func ReadOutput() (s string) -func RewriteStdout() -func RestoreStdout(printData ...bool) (s string) -func RewriteStderr() -func RestoreStderr(printData ...bool) (s string) +func DiscardStdout() error +func ReadOutput() (s string) +func RewriteStdout() +func RestoreStdout(printData ...bool) (s string) +func RewriteStderr() +func RestoreStderr(printData ...bool) (s string) +func SetTimeLocal(tl *time.Location) +func SetTimeLocalUTC() +func RestoreTimeLocal() // source at testutil/writer.go -func NewTestWriter() *TestWriter +func NewTestWriter() *TestWriter +func NewDirEnt(fpath string, isDir ...bool) *fakeobj.DirEntry ``` ### Timex @@ -1414,57 +1539,65 @@ func NewTestWriter() *TestWriter Provides an enhanced time.Time implementation, and add more commonly used functional methods. ```go +// source at timex/check.go +func IsDuration(s string) bool +func InRange(dst, start, end time.Time) bool +// source at timex/conv.go +func Elapsed(start, end time.Time) string +func ElapsedNow(start time.Time) string +func FromNow(t time.Time) string +func FromNowWith(u time.Time, tms []TimeMessage) string +func HowLongAgo(diffSec int64) string +func HowLongAgo2(diffSec int64, tms []TimeMessage) string +func ToTime(s string, layouts ...string) (time.Time, error) +func ToDur(s string) (time.Duration, error) +func ToDuration(s string) (time.Duration, error) +func TryToTime(s string, bt time.Time) (time.Time, error) +func ParseRange(expr string, opt *ParseRangeOpt) (start, end time.Time, err error) // source at timex/gotime.go -func SetLocalByName(tzName string) error -func NowAddDay(day int) time.Time -func NowAddHour(hour int) time.Time -func NowAddMinutes(minutes int) time.Time -func NowAddSec(seconds int) time.Time -func NowAddSeconds(seconds int) time.Time -func NowHourStart() time.Time -func NowHourEnd() time.Time -func AddDay(t time.Time, day int) time.Time -func AddHour(t time.Time, hour int) time.Time -func AddMinutes(t time.Time, minutes int) time.Time -func AddSeconds(t time.Time, seconds int) time.Time -func AddSec(t time.Time, seconds int) time.Time -func HourStart(t time.Time) time.Time -func HourEnd(t time.Time) time.Time -func DayStart(t time.Time) time.Time -func DayEnd(t time.Time) time.Time -func TodayStart() time.Time -func TodayEnd() time.Time +func SetLocalByName(tzName string) error +func NowAddDay(day int) time.Time +func NowAddHour(hour int) time.Time +func NowAddMinutes(minutes int) time.Time +func NowAddSec(seconds int) time.Time +func NowAddSeconds(seconds int) time.Time +func NowHourStart() time.Time +func NowHourEnd() time.Time +func AddDay(t time.Time, day int) time.Time +func AddHour(t time.Time, hour int) time.Time +func AddMinutes(t time.Time, minutes int) time.Time +func AddSeconds(t time.Time, seconds int) time.Time +func AddSec(t time.Time, seconds int) time.Time +func HourStart(t time.Time) time.Time +func HourEnd(t time.Time) time.Time +func DayStart(t time.Time) time.Time +func DayEnd(t time.Time) time.Time +func TodayStart() time.Time +func TodayEnd() time.Time // source at timex/template.go -func ToLayout(template string) string +func ToLayout(template string) string // source at timex/timex.go -func Now() *Time -func New(t time.Time) *Time -func Wrap(t time.Time) *Time -func FromTime(t time.Time) *Time -func Local() *Time -func FromUnix(sec int64) *Time -func FromDate(s string, template ...string) (*Time, error) -func FromString(s string, layouts ...string) (*Time, error) -func LocalByName(tzName string) *Time +func Now() *Time +func New(t time.Time) *Time +func Wrap(t time.Time) *Time +func FromTime(t time.Time) *Time +func Local() *Time +func FromUnix(sec int64) *Time +func FromDate(s string, template ...string) (*Time, error) +func FromString(s string, layouts ...string) (*Time, error) +func LocalByName(tzName string) *Time // source at timex/util.go -func NowUnix() int64 -func Format(t time.Time) string -func FormatBy(t time.Time, layout string) string -func Date(t time.Time, template ...string) string -func Datetime(t time.Time, template ...string) string -func DateFormat(t time.Time, template string) string -func FormatByTpl(t time.Time, template string) string -func FormatUnix(sec int64, layout ...string) string -func FormatUnixBy(sec int64, layout string) string -func FormatUnixByTpl(sec int64, template ...string) string -func HowLongAgo(sec int64) string -func ToTime(s string, layouts ...string) (time.Time, error) -func ToDur(s string) (time.Duration, error) -func ToDuration(s string) (time.Duration, error) -func IsDuration(s string) bool -func TryToTime(s string, bt time.Time) (time.Time, error) -func InRange(dst, start, end time.Time) bool -func ParseRange(expr string, opt *ParseRangeOpt) (start, end time.Time, err error) +func NowUnix() int64 +func NowDate(template ...string) string +func Format(t time.Time) string +func FormatBy(t time.Time, layout string) string +func Date(t time.Time, template ...string) string +func Datetime(t time.Time, template ...string) string +func DateFormat(t time.Time, template string) string +func FormatByTpl(t time.Time, template string) string +func FormatUnix(sec int64, layout ...string) string +func FormatUnixBy(sec int64, layout string) string +func FormatUnixByTpl(sec int64, template ...string) string ``` #### Timex Usage diff --git a/vendor/github.com/gookit/goutil/README.zh-CN.md b/vendor/github.com/gookit/goutil/README.zh-CN.md index 49a46c633..318d4976d 100644 --- a/vendor/github.com/gookit/goutil/README.zh-CN.md +++ b/vendor/github.com/gookit/goutil/README.zh-CN.md @@ -7,39 +7,42 @@ [![Coverage Status](https://coveralls.io/repos/github/gookit/goutil/badge.svg?branch=master)](https://coveralls.io/github/gookit/goutil?branch=master) [![Go Reference](https://pkg.go.dev/badge/github.com/gookit/goutil.svg)](https://pkg.go.dev/github.com/gookit/goutil) -`goutil` Go 常用功能的扩展工具库(**600+**)。包含:数字,byte, 字符串,slice/数组,Map,结构体,反射,文本,文件,错误,时间日期,测试,特殊处理,格式化,常用信息获取等等。 +`goutil` Go 常用功能的扩展工具库(**700+**)。包含:数字,byte, 字符串,slice/数组,Map,结构体,反射,文本,文件,错误,时间日期,测试,特殊处理,格式化,常用信息获取等等。 > **[EN README](README.md)** **基础工具包** -- [`arrutil`](./arrutil) array/slice 相关操作的函数工具包 如:类型转换,元素检查等等 -- [`cliutil`](./cliutil) CLI 的一些工具函数包. eg: read input, exec command - - [cmdline](./cliutil/cmdline) 提供 cmdline 解析,args 构建到 cmdline -- [`envutil`](./envutil) ENV 信息获取判断工具包. eg: get one, get info, parse var -- [`fmtutil`](./fmtutil) 格式化数据工具函数 eg:数据size -- [`fsutil`](./fsutil) 文件系统操作相关的工具函数包. eg: file and dir check, operate -- [`jsonutil`](./jsonutil) 一些用于快速读取、写入、编码、解码 JSON 数据的实用函数。 -- [`maputil`](./maputil) map 相关操作的函数工具包. eg: convert, sub-value get, simple merge -- [`mathutil`](./mathutil) int/number 相关操作的函数工具包. eg: convert, math calc, random -- [`reflects`](./reflects) 提供一些扩展性的反射使用工具函数. -- [`stdutil`](./stdutil) 提供一些常用的 std util 函数。 -- [`structs`](./structs) 为 struct 提供一些扩展 util 函数。 eg: tag parse, struct data -- [`strutil`](./strutil) string 相关操作的函数工具包. eg: bytes, check, convert, encode, format and more -- [`sysutil`](./sysutil) system 相关操作的函数工具包. eg: sysenv, exec, user, process +- [`arrutil`](arrutil) array/slice 相关操作的函数工具包 如:类型转换,元素检查等等 +- [`cliutil`](cliutil) CLI 的一些工具函数包. eg: read input, exec command + - [cmdline](cliutil/cmdline) 提供 cmdline 解析,args 构建到 cmdline +- [`envutil`](envutil) ENV 信息获取判断工具包. eg: get one, get info, parse var +- [`fmtutil`](fmtutil) 格式化数据工具函数 eg:数据size +- [`fsutil`](fsutil) 文件系统操作相关的工具函数包. eg: file and dir check, operate +- [`goinfo`](goinfo) 提供一些与Go info, runtime 相关的工具函数。 +- [`jsonutil`](jsonutil) 一些用于快速读取、写入、编码、解码 JSON 数据的实用函数。 +- [`maputil`](maputil) map 相关操作的函数工具包. eg: convert, sub-value get, simple merge +- [`mathutil`](mathutil) int/number 相关操作的函数工具包. eg: convert, math calc, random +- [`netutil`](netutil) Network util functions. eg: Ip, IpV4, IpV6, Mac, Port, Hostname, etc. +- [`reflects`](reflects) 提供一些扩展性的反射使用工具函数. +- [`structs`](structs) 为 struct 提供一些扩展 util 函数。 eg: tag parse, struct data +- [`strutil`](strutil) string 相关操作的函数工具包. eg: bytes, check, convert, encode, format and more +- [`sysutil`](sysutil) system 相关操作的函数工具包. eg: sysenv, exec, user, process **扩展工具包** - [`cflag`](./cflag): 包装和扩展 go `flag.FlagSet` 以方便快速的构建简单的命令行应用程序 - [`dump`](./dump) GO变量打印工具,打印 slice, map 会自动换行显示每个元素,同时会显示打印调用位置 +- [`encodes`](encodes): Provide some encoding/decoding, hash, crypto util functions. eg: base64, hex, etc. - [`errorx`](./errorx) 为 go 提供增强的错误实现,允许带有堆栈跟踪信息和包装另一个错误。 - [`finder`](./fsutil/finder) 提供简单方便的file/dir查找功能,支持过滤、排除、匹配、忽略等。 -- netutil: - - `netutil/httpreq` 包装 http.Client 实现的更加易于使用的HTTP客户端 -- strutil: +- netutil 子包: + - `netutil/httpreq` 包装 http.Client 实现的更加易于使用的HTTP客户端, 和一些 http 工具函数 +- strutil 子包: - [textscan](strutil/textscan) 实现了一个快速扫描和分析文本内容的解析器. 可用于解析 INI, Properties 等格式内容 - [textutil](strutil/textutil) 提供一些常用的扩展文本处理功能函数。 -- sysutil: +- [syncs](syncs) 提供一些同步、协程、信号相关的工具函数. +- sysutil 子包: - [clipboard](sysutil/clipboard) 提供简单的剪贴板读写操作工具库 - [cmdr](sysutil/cmdr) 提供快速构建和运行一个cmd,批量运行多个cmd任务 - [process](sysutil/process) 提供一些进程操作相关的实用功能。 @@ -48,7 +51,7 @@ - [fakeobj](testutil/fakeobj) 提供一些接口的假的实现,用于模拟测试. 例如 fs.File, fs.FileInfo, fs.DirEntry 等等. - [`timex`](timex) 提供增强的 time.Time 实现。添加更多常用的功能方法 - 提供类似 `Y-m-d H:i:s` 的日期时间格式解析处理 - - 例如: DayStart(), DayAfter(), DayAgo(), DateFormat() 等等 + - 常用时间方法。例如: DayStart(), DayAfter(), DayAgo(), DateFormat() 等等 ## GoDoc @@ -82,6 +85,16 @@ i64Val = goutil.Int64("-2") // -2 u64Val = goutil.Uint("2") // 2 ``` +### Dump go variable + +```go +dump.Print(somevar, somevar2, ...) +``` + +**dump nested struct** + +![preview-nested-struct](dump/_examples/preview-nested-struct.png) + ## Packages ### Array and Slice @@ -90,69 +103,82 @@ u64Val = goutil.Uint("2") // 2 ```go // source at arrutil/arrutil.go -func Reverse(ss []string) -func StringsRemove(ss []string, s string) []string -func StringsFilter(ss []string, filter ...func(s string) bool) []string -func StringsMap(ss []string, mapFn func(s string) string) []string -func TrimStrings(ss []string, cutSet ...string) []string -func GetRandomOne[T any](arr []T) T -func RandomOne[T any](arr []T) T -func Unique[T ~string | comdef.XintOrFloat](list []T) []T -func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int +func GetRandomOne[T any](arr []T) T +func RandomOne[T any](arr []T) T // source at arrutil/check.go -func IntsHas(ints []int, val int) bool -func Int64sHas(ints []int64, val int64) bool -func InStrings(elem string, ss []string) bool -func StringsHas(ss []string, val string) bool -func NotIn[T comdef.ScalarType](value T, list []T) bool -func In[T comdef.ScalarType](value T, list []T) bool -func ContainsAll[T comdef.ScalarType](list, values []T) bool -func IsSubList[T comdef.ScalarType](values, list []T) bool -func IsParent[T comdef.ScalarType](values, list []T) bool -func HasValue(arr, val any) bool -func Contains(arr, val any) bool -func NotContains(arr, val any) bool +func SliceHas[T comdef.ScalarType](slice []T, val T) bool +func IntsHas[T comdef.Integer](ints []T, val T) bool +func Int64sHas(ints []int64, val int64) bool +func StringsHas[T ~string](ss []T, val T) bool +func InStrings[T ~string](elem T, ss []T) bool +func NotIn[T comdef.ScalarType](value T, list []T) bool +func In[T comdef.ScalarType](value T, list []T) bool +func ContainsAll[T comdef.ScalarType](list, values []T) bool +func IsSubList[T comdef.ScalarType](values, list []T) bool +func IsParent[T comdef.ScalarType](values, list []T) bool +func HasValue(arr, val any) bool +func Contains(arr, val any) bool +func NotContains(arr, val any) bool // source at arrutil/collection.go -func TwowaySearch(data any, item any, fn Comparer) (int, error) -func MakeEmptySlice(itemType reflect.Type) any -func CloneSlice(data any) any -func Differences[T any](first, second []T, fn Comparer) []T -func Excepts(first, second any, fn Comparer) any -func Intersects(first any, second any, fn Comparer) any -func Union(first, second any, fn Comparer) any -func Find(source any, fn Predicate) (any, error) -func FindOrDefault(source any, fn Predicate, defaultValue any) any -func TakeWhile(data any, fn Predicate) any -func ExceptWhile(data any, fn Predicate) any -// source at arrutil/collection_gte118.go -func Map[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V -func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V +func StringEqualsComparer(a, b string) int +func ValueEqualsComparer[T comdef.Compared](a, b T) int +func ReflectEqualsComparer[T any](a, b T) int +func ElemTypeEqualsComparer[T any](a, b T) int +func TwowaySearch[T any](data []T, item T, fn Comparer[T]) (int, error) +func CloneSlice[T any](data []T) []T +func Diff[T any](first, second []T, fn Comparer[T]) []T +func Differences[T any](first, second []T, fn Comparer[T]) []T +func Excepts[T any](first, second []T, fn Comparer[T]) []T +func Intersects[T any](first, second []T, fn Comparer[T]) []T +func Union[T any](first, second []T, fn Comparer[T]) []T +func Find[T any](source []T, fn Predicate[T]) (v T, err error) +func FindOrDefault[T any](source []T, fn Predicate[T], defaultValue T) T +func TakeWhile[T any](data []T, fn Predicate[T]) []T +func ExceptWhile[T any](data []T, fn Predicate[T]) []T // source at arrutil/convert.go -func JoinStrings(sep string, ss ...string) string -func StringsJoin(sep string, ss ...string) string -func JoinSlice(sep string, arr ...any) string -func ToInt64s(arr any) (ret []int64, err error) -func MustToInt64s(arr any) []int64 -func SliceToInt64s(arr []any) []int64 -func StringsAsInts(ss []string) []int -func StringsToInts(ss []string) (ints []int, err error) -func StringsTryInts(ss []string) (ints []int, err error) -func AnyToSlice(sl any) (ls []any, err error) -func AnyToStrings(arr any) []string -func MustToStrings(arr any) []string -func StringsToSlice(ss []string) []any -func ToStrings(arr any) (ret []string, err error) -func SliceToStrings(arr []any) []string -func QuietStrings(arr []any) []string -func ConvType[T any, R any](arr []T, newElemTyp R) ([]R, error) -func AnyToString(arr any) string -func SliceToString(arr ...any) string -func ToString(arr []any) string -func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V -func CombineToSMap(keys, values []string) map[string]string +func JoinStrings(sep string, ss ...string) string +func StringsJoin(sep string, ss ...string) string +func JoinTyped[T any](sep string, arr ...T) string +func JoinSlice(sep string, arr ...any) string +func IntsToString[T comdef.Integer](ints []T) string +func ToInt64s(arr any) (ret []int64, err error) +func MustToInt64s(arr any) []int64 +func SliceToInt64s(arr []any) []int64 +func AnyToSlice(sl any) (ls []any, err error) +func AnyToStrings(arr any) []string +func MustToStrings(arr any) []string +func ToStrings(arr any) (ret []string, err error) +func SliceToStrings(arr []any) []string +func QuietStrings(arr []any) []string +func ConvType[T any, R any](arr []T, newElemTyp R) ([]R, error) +func AnyToString(arr any) string +func SliceToString(arr ...any) string +func ToString[T any](arr []T) string +func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V +func CombineToSMap(keys, values []string) map[string]string // source at arrutil/format.go -func NewFormatter(arr any) *ArrFormatter -func FormatIndent(arr any, indent string) string +func NewFormatter(arr any) *ArrFormatter +func FormatIndent(arr any, indent string) string +// source at arrutil/process.go +func Reverse[T any](ls []T) +func Remove[T comdef.Compared](ls []T, val T) []T +func Filter[T any](ls []T, filter ...comdef.MatchFunc[T]) []T +func Map[T any, V any](list []T, mapFn MapFn[T, V]) []V +func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V +func Unique[T ~string | comdef.XintOrFloat](list []T) []T +func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int +// source at arrutil/strings.go +func StringsToAnys(ss []string) []any +func StringsToSlice(ss []string) []any +func StringsAsInts(ss []string) []int +func StringsToInts(ss []string) (ints []int, err error) +func StringsTryInts(ss []string) (ints []int, err error) +func StringsUnique(ss []string) []string +func StringsContains(ss []string, s string) bool +func StringsRemove(ss []string, s string) []string +func StringsFilter(ss []string, filter ...comdef.StringMatchFunc) []string +func StringsMap(ss []string, mapFn func(s string) string) []string +func TrimStrings(ss []string, cutSet ...string) []string ``` #### ArrUtil Usage @@ -182,24 +208,30 @@ ss, err := arrutil.ToStrings([]int{1, 2}) // ss: []string{"1", "2"} ```go // source at byteutil/buffer.go -func NewBuffer() *Buffer +func NewBuffer() *Buffer // source at byteutil/byteutil.go -func Random(length int) ([]byte, error) -func FirstLine(bs []byte) []byte -func StrOrErr(bs []byte, err error) (string, error) -func SafeString(bs []byte, err error) string -func String(b []byte) string -func ToString(b []byte) string -func AppendAny(dst []byte, v any) []byte -func Cut(bs []byte, sep byte) (before, after []byte, found bool) -// source at byteutil/bytex.go -func Md5(src any) []byte +func Md5(src any) []byte +func ShortMd5(src any) []byte +func Random(length int) ([]byte, error) +func FirstLine(bs []byte) []byte +func AppendAny(dst []byte, v any) []byte +func Cut(bs []byte, sep byte) (before, after []byte, found bool) +func SafeCut(bs []byte, sep byte) (before, after []byte) +func SafeCuts(bs []byte, sep []byte) (before, after []byte) // source at byteutil/check.go -func IsNumChar(c byte) bool +func IsNumChar(c byte) bool +// source at byteutil/conv.go +func StrOrErr(bs []byte, err error) (string, error) +func SafeString(bs []byte, err error) string +func String(b []byte) string +func ToString(b []byte) string +func ToBytes(v any) ([]byte, error) +func SafeBytes(v any) []byte +func ToBytesWithFunc(v any, usrFn ToBytesFunc) ([]byte, error) // source at byteutil/encoder.go -func NewStdEncoder(encFn func(src []byte) []byte, decFn func(src []byte) ([]byte, error)) *StdEncoder +func NewStdEncoder(encFn BytesEncodeFunc, decFn BytesDecodeFunc) *StdEncoder // source at byteutil/pool.go -func NewChanPool(maxSize int, width int, capWidth int) *ChanPool +func NewChanPool(chSize int, width int, capWidth int) *ChanPool ``` ### Cflag @@ -208,30 +240,34 @@ func NewChanPool(maxSize int, width int, capWidth int) *ChanPool ```go // source at cflag/app.go -func NewApp(fns ...func(app *App)) *App -func NewCmd(name, desc string) *Cmd +func NewApp(fns ...func(app *App)) *App +func NewCmd(name, desc string) *Cmd // source at cflag/cflag.go -func SetDebug(open bool) -func New(fns ...func(c *CFlags)) *CFlags -func NewEmpty(fns ...func(c *CFlags)) *CFlags -func WithDesc(desc string) func(c *CFlags) -func WithVersion(version string) func(c *CFlags) +func SetDebug(open bool) +func New(fns ...func(c *CFlags)) *CFlags +func NewEmpty(fns ...func(c *CFlags)) *CFlags +func WithDesc(desc string) func(c *CFlags) +func WithVersion(version string) func(c *CFlags) // source at cflag/ext.go -func NewEnumString(enum ...string) EnumString -func NewKVString() KVString +func LimitInt(min, max int) comdef.IntCheckFunc +func NewIntVar(checkFn comdef.IntCheckFunc) IntVar +func NewStrVar(checkFn comdef.StrCheckFunc) StrVar +func NewEnumString(enum ...string) EnumString +func NewKVString() KVString +func Value // source at cflag/optarg.go -func NewArg(name, desc string, required bool) *FlagArg +func NewArg(name, desc string, required bool) *FlagArg // source at cflag/util.go -func IsGoodName(name string) bool -func IsZeroValue(opt *flag.Flag, value string) (bool, bool) -func AddPrefix(name string) string -func AddPrefixes(name string, shorts []string) string -func AddPrefixes2(name string, shorts []string, nameAtEnd bool) string -func SplitShortcut(shortcut string) []string -func FilterNames(names []string) []string -func IsFlagHelpErr(err error) bool -func WrapColorForCode(s string) string -func ReplaceShorts(args []string, shortsMap map[string]string) []string +func IsGoodName(name string) bool +func IsZeroValue(opt *flag.Flag, value string) (bool, bool) +func AddPrefix(name string) string +func AddPrefixes(name string, shorts []string) string +func AddPrefixes2(name string, shorts []string, nameAtEnd bool) string +func SplitShortcut(shortcut string) []string +func FilterNames(names []string) []string +func IsFlagHelpErr(err error) bool +func WrapColorForCode(s string) string +func ReplaceShorts(args []string, shortsMap map[string]string) []string ``` #### `cflag` Usage @@ -244,72 +280,39 @@ func ReplaceShorts(args []string, shortsMap map[string]string) []string ```go // source at cliutil/cliutil.go -func LineBuild(binFile string, args []string) string -func BuildLine(binFile string, args []string) string -func String2OSArgs(line string) []string -func StringToOSArgs(line string) []string -func ParseLine(line string) []string -func QuickExec(cmdLine string, workDir ...string) (string, error) -func ExecLine(cmdLine string, workDir ...string) (string, error) -func ExecCmd(binName string, args []string, workDir ...string) (string, error) -func ExecCommand(binName string, args []string, workDir ...string) (string, error) -func ShellExec(cmdLine string, shells ...string) (string, error) -func CurrentShell(onlyName bool) (path string) -func HasShellEnv(shell string) bool -func BuildOptionHelpName(names []string) string -func ShellQuote(s string) string -func OutputLines(output string) []string -// source at cliutil/color_print.go -func Redp(a ...any) -func Redf(format string, a ...any) -func Redln(a ...any) -func Bluep(a ...any) -func Bluef(format string, a ...any) -func Blueln(a ...any) -func Cyanp(a ...any) -func Cyanf(format string, a ...any) -func Cyanln(a ...any) -func Grayp(a ...any) -func Grayf(format string, a ...any) -func Grayln(a ...any) -func Greenp(a ...any) -func Greenf(format string, a ...any) -func Greenln(a ...any) -func Yellowp(a ...any) -func Yellowf(format string, a ...any) -func Yellowln(a ...any) -func Magentap(a ...any) -func Magentaf(format string, a ...any) -func Magentaln(a ...any) -func Infop(a ...any) -func Infof(format string, a ...any) -func Infoln(a ...any) -func Successp(a ...any) -func Successf(format string, a ...any) -func Successln(a ...any) -func Errorp(a ...any) -func Errorf(format string, a ...any) -func Errorln(a ...any) -func Warnp(a ...any) -func Warnf(format string, a ...any) -func Warnln(a ...any) +func SplitMulti(ss []string, sep string) []string +func LineBuild(binFile string, args []string) string +func BuildLine(binFile string, args []string) string +func String2OSArgs(line string) []string +func StringToOSArgs(line string) []string +func ParseLine(line string) []string +func QuickExec(cmdLine string, workDir ...string) (string, error) +func ExecLine(cmdLine string, workDir ...string) (string, error) +func ExecCmd(binName string, args []string, workDir ...string) (string, error) +func ExecCommand(binName string, args []string, workDir ...string) (string, error) +func ShellExec(cmdLine string, shells ...string) (string, error) +func CurrentShell(onlyName bool) (path string) +func HasShellEnv(shell string) bool +func BuildOptionHelpName(names []string) string +func ShellQuote(s string) string +func OutputLines(output string) []string // source at cliutil/info.go -func Workdir() string -func BinDir() string -func BinFile() string -func BinName() string -func GetTermSize(refresh ...bool) (w int, h int) +func Workdir() string +func BinDir() string +func BinFile() string +func BinName() string +func GetTermSize(refresh ...bool) (w int, h int) // source at cliutil/read.go -func ReadInput(question string) (string, error) -func ReadLine(question string) (string, error) -func ReadFirst(question string) (string, error) -func ReadFirstByte(question string) (byte, error) -func ReadFirstRune(question string) (rune, error) -func ReadAsBool(tip string, defVal bool) bool -func ReadPassword(question ...string) string -func Confirm(tip string, defVal ...bool) bool -func InputIsYes(ans string) bool -func ByteIsYes(ans byte) bool +func ReadInput(question string) (string, error) +func ReadLine(question string) (string, error) +func ReadFirst(question string) (string, error) +func ReadFirstByte(question string) (byte, error) +func ReadFirstRune(question string) (rune, error) +func ReadAsBool(tip string, defVal bool) bool +func Confirm(tip string, defVal ...bool) bool +func InputIsYes(ans string) bool +func ByteIsYes(ans byte) bool +func ReadPassword(question ...string) string ``` #### CLI Util Usage @@ -373,30 +376,30 @@ Build line: ./myapp -a val0 -m "this is message" arg0 ```go // source at dump/dump.go -func Std() *Dumper -func Reset() -func Config(fns ...OptionFunc) -func Print(vs ...any) -func Println(vs ...any) -func Fprint(w io.Writer, vs ...any) -func Std2() *Dumper -func Reset2() -func Format(vs ...any) string -func NoLoc(vs ...any) -func Clear(vs ...any) +func Std() *Dumper +func Reset() +func Config(fns ...OptionFunc) +func Print(vs ...any) +func Println(vs ...any) +func Fprint(w io.Writer, vs ...any) +func Std2() *Dumper +func Reset2() +func Format(vs ...any) string +func NoLoc(vs ...any) +func Clear(vs ...any) // source at dump/dumper.go -func NewDumper(out io.Writer, skip int) *Dumper -func NewWithOptions(fns ...OptionFunc) *Dumper +func NewDumper(out io.Writer, skip int) *Dumper +func NewWithOptions(fns ...OptionFunc) *Dumper // source at dump/options.go -func NewDefaultOptions(out io.Writer, skip int) *Options -func SkipNilField() OptionFunc -func SkipPrivate() OptionFunc -func BytesAsString() OptionFunc -func WithCallerSkip(skip int) OptionFunc -func WithoutPosition() OptionFunc -func WithoutOutput(out io.Writer) OptionFunc -func WithoutColor() OptionFunc -func WithoutType() OptionFunc +func NewDefaultOptions(out io.Writer, skip int) *Options +func SkipNilField() OptionFunc +func SkipPrivate() OptionFunc +func BytesAsString() OptionFunc +func WithCallerSkip(skip int) OptionFunc +func WithoutPosition() OptionFunc +func WithoutOutput(out io.Writer) OptionFunc +func WithoutColor() OptionFunc +func WithoutType() OptionFunc ``` #### Examples @@ -442,44 +445,59 @@ Preview: ![](dump/_examples/preview-nested-struct.png) +### Encodes + +> Package `github.com/gookit/goutil/encodes` + +```go +// source at encodes/encodes.go +func B32Encode(str string) string +func B32Decode(str string) string +func B64Encode(str string) string +func B64EncodeBytes(src []byte) []byte +func B64Decode(str string) string +func B64DecodeBytes(str []byte) []byte +``` + ### ENV/Environment > Package `github.com/gookit/goutil/envutil` ```go // source at envutil/envutil.go -func VarReplace(s string) string -func VarParse(val string) string -func ParseEnvValue(val string) string -func ParseValue(val string) (newVal string) -func SetEnvMap(mp map[string]string) -func SetEnvs(kvPairs ...string) -func UnsetEnvs(keys ...string) +func VarReplace(s string) string +func ParseOrErr(val string) (string, error) +func ParseValue(val string) string +func VarParse(val string) string +func ParseEnvValue(val string) string +func SetEnvMap(mp map[string]string) +func SetEnvs(kvPairs ...string) +func UnsetEnvs(keys ...string) // source at envutil/get.go -func Getenv(name string, def ...string) string -func GetInt(name string, def ...int) int -func GetBool(name string, def ...bool) bool -func GetMulti(names ...string) map[string]string -func EnvPaths() []string -func EnvMap() map[string]string -func Environ() map[string]string -func SearchEnvKeys(keywords string) map[string]string -func SearchEnv(keywords string, matchValue bool) map[string]string +func Getenv(name string, def ...string) string +func GetInt(name string, def ...int) int +func GetBool(name string, def ...bool) bool +func GetMulti(names ...string) map[string]string +func EnvPaths() []string +func EnvMap() map[string]string +func Environ() map[string]string +func SearchEnvKeys(keywords string) map[string]string +func SearchEnv(keywords string, matchValue bool) map[string]string // source at envutil/info.go -func IsWin() bool -func IsWindows() bool -func IsMac() bool -func IsLinux() bool -func IsMSys() bool -func IsWSL() bool -func IsTerminal(fd uintptr) bool -func StdIsTerminal() bool -func IsConsole(out io.Writer) bool -func HasShellEnv(shell string) bool -func IsSupportColor() bool -func IsSupport256Color() bool -func IsSupportTrueColor() bool -func IsGithubActions() bool +func IsWin() bool +func IsWindows() bool +func IsMac() bool +func IsLinux() bool +func IsMSys() bool +func IsWSL() bool +func IsTerminal(fd uintptr) bool +func StdIsTerminal() bool +func IsConsole(out io.Writer) bool +func HasShellEnv(shell string) bool +func IsSupportColor() bool +func IsSupport256Color() bool +func IsSupportTrueColor() bool +func IsGithubActions() bool ``` #### ENV Util Usage @@ -511,49 +529,51 @@ envutil.ParseValue("${ENV_NAME | defValue}") ```go // source at errorx/assert.go -func IsTrue(result bool, fmtAndArgs ...any) error -func IsFalse(result bool, fmtAndArgs ...any) error -func IsIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error -func NotIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error +func IsTrue(result bool, fmtAndArgs ...any) error +func IsFalse(result bool, fmtAndArgs ...any) error +func IsIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error +func NotIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error // source at errorx/errors.go -func NewR(code int, msg string) ErrorR -func Fail(code int, msg string) ErrorR -func Failf(code int, tpl string, v ...any) ErrorR -func Suc(msg string) ErrorR +func NewR(code int, msg string) ErrorR +func Fail(code int, msg string) ErrorR +func Failf(code int, tpl string, v ...any) ErrorR +func Suc(msg string) ErrorR // source at errorx/errorx.go -func New(msg string) error -func Newf(tpl string, vars ...any) error -func Errorf(tpl string, vars ...any) error -func With(err error, msg string) error -func Withf(err error, tpl string, vars ...any) error -func WithPrev(err error, msg string) error -func WithPrevf(err error, tpl string, vars ...any) error -func WithStack(err error) error -func Traced(err error) error -func Stacked(err error) error -func WithOptions(msg string, fns ...func(opt *ErrStackOpt)) error -func Wrap(err error, msg string) error -func Wrapf(err error, tpl string, vars ...any) error +func New(msg string) error +func Newf(tpl string, vars ...any) error +func Errorf(tpl string, vars ...any) error +func With(err error, msg string) error +func Withf(err error, tpl string, vars ...any) error +func WithPrev(err error, msg string) error +func WithPrevf(err error, tpl string, vars ...any) error +func WithStack(err error) error +func Traced(err error) error +func Stacked(err error) error +func WithOptions(msg string, fns ...func(opt *ErrStackOpt)) error +func Wrap(err error, msg string) error +func Wrapf(err error, tpl string, vars ...any) error // source at errorx/stack.go -func FuncForPC(pc uintptr) *Func -func ResetStdOpt() -func Config(fns ...func(opt *ErrStackOpt)) -func SkipDepth(skipDepth int) func(opt *ErrStackOpt) -func TraceDepth(traceDepth int) func(opt *ErrStackOpt) +func FuncForPC(pc uintptr) *Func +func ResetStdOpt() +func Config(fns ...func(opt *ErrStackOpt)) +func SkipDepth(skipDepth int) func(opt *ErrStackOpt) +func TraceDepth(traceDepth int) func(opt *ErrStackOpt) // source at errorx/util.go -func Err(msg string) error -func Raw(msg string) error -func Ef(tpl string, vars ...any) error -func Errf(tpl string, vars ...any) error -func Rawf(tpl string, vars ...any) error -func Cause(err error) error -func Unwrap(err error) error -func Previous(err error) error -func ToErrorX(err error) (ex *ErrorX, ok bool) -func Has(err, target error) bool -func Is(err, target error) bool -func To(err error, target any) bool -func As(err error, target any) bool +func Err(msg string) error +func Raw(msg string) error +func Ef(tpl string, vars ...any) error +func Errf(tpl string, vars ...any) error +func Rawf(tpl string, vars ...any) error +func Cause(err error) error +func Unwrap(err error) error +func Previous(err error) error +func IsErrorX(err error) (ok bool) +func ToErrorX(err error) (ex *ErrorX, ok bool) +func MustEX(err error) *ErrorX +func Has(err, target error) bool +func Is(err, target error) bool +func To(err error, target any) bool +func As(err error, target any) bool ``` #### Errorx 使用示例 @@ -638,17 +658,17 @@ runtime.goexit() ```go // source at fmtutil/fmtutil.go -func StringOrJSON(v any) ([]byte, error) +func StringOrJSON(v any) ([]byte, error) // source at fmtutil/format.go -func DataSize(size uint64) string -func SizeToString(size uint64) string -func StringToByte(sizeStr string) uint64 -func ParseByte(sizeStr string) uint64 -func PrettyJSON(v any) (string, error) -func StringsToInts(ss []string) (ints []int, err error) -func ArgsWithSpaces(vs []any) (message string) +func DataSize(size uint64) string +func SizeToString(size uint64) string +func StringToByte(sizeStr string) uint64 +func ParseByte(sizeStr string) uint64 +func PrettyJSON(v any) (string, error) +func StringsToInts(ss []string) (ints []int, err error) +func ArgsWithSpaces(vs []any) (message string) // source at fmtutil/time.go -func HowLongAgo(sec int64) string +func HowLongAgo(sec int64) string ``` ### File System @@ -657,96 +677,118 @@ func HowLongAgo(sec int64) string ```go // source at fsutil/check.go -func PathExists(path string) bool -func IsDir(path string) bool -func FileExists(path string) bool -func IsFile(path string) bool -func IsAbsPath(aPath string) bool -func IsImageFile(path string) bool -func IsZipFile(filepath string) bool -func PathMatch(pattern, s string) bool +func PathExists(path string) bool +func IsDir(path string) bool +func FileExists(path string) bool +func IsFile(path string) bool +func IsAbsPath(aPath string) bool +func IsEmptyDir(dirPath string) bool +func IsImageFile(path string) bool +func IsZipFile(filepath string) bool +func PathMatch(pattern, s string) bool +// source at fsutil/define.go +func NewEntry(fPath string, ent fs.DirEntry) Entry +func NewFileInfo(fPath string, info fs.FileInfo) FileInfo // source at fsutil/find.go -func SearchNameUp(dirPath, name string) string -func SearchNameUpx(dirPath, name string) (string, bool) -func WalkDir(dir string, fn fs.WalkDirFunc) error -func Glob(pattern string, fls ...comdef.StringMatchFunc) []string -func GlobWithFunc(pattern string, fn func(filePath string) error) (err error) -func OnlyFindDir(_ string, ent fs.DirEntry) bool -func OnlyFindFile(_ string, ent fs.DirEntry) bool -func ExcludeNames(names ...string) FilterFunc -func IncludeSuffix(ss ...string) FilterFunc -func ExcludeDotFile(_ string, ent fs.DirEntry) bool -func ExcludeSuffix(ss ...string) FilterFunc -func ApplyFilters(fPath string, ent fs.DirEntry, filters []FilterFunc) bool -func FindInDir(dir string, handleFn HandleFunc, filters ...FilterFunc) (e error) +func FilePathInDirs(file string, dirs ...string) string +func FirstExists(paths ...string) string +func FirstExistsDir(paths ...string) string +func FirstExistsFile(paths ...string) string +func MatchPaths(paths []string, matcher PathMatchFunc) []string +func MatchFirst(paths []string, matcher PathMatchFunc, defaultPath string) string +func SearchNameUp(dirPath, name string) string +func SearchNameUpx(dirPath, name string) (string, bool) +func WalkDir(dir string, fn fs.WalkDirFunc) error +func Glob(pattern string, fls ...NameMatchFunc) []string +func GlobWithFunc(pattern string, fn func(filePath string) error) (err error) +func OnlyFindDir(_ string, ent fs.DirEntry) bool +func OnlyFindFile(_ string, ent fs.DirEntry) bool +func ExcludeNames(names ...string) FilterFunc +func IncludeSuffix(ss ...string) FilterFunc +func ExcludeDotFile(_ string, ent fs.DirEntry) bool +func ExcludeSuffix(ss ...string) FilterFunc +func ApplyFilters(fPath string, ent fs.DirEntry, filters []FilterFunc) bool +func FindInDir(dir string, handleFn HandleFunc, filters ...FilterFunc) (e error) // source at fsutil/fsutil.go -func OSTempFile(pattern string) (*os.File, error) -func TempFile(dir, pattern string) (*os.File, error) -func OSTempDir(pattern string) (string, error) -func TempDir(dir, pattern string) (string, error) -func MimeType(path string) (mime string) -func ReaderMimeType(r io.Reader) (mime string) -func JoinPaths(elem ...string) string -func JoinSubPaths(basePath string, elem ...string) string -func SlashPath(path string) string -func UnixPath(path string) string -func ToAbsPath(p string) string +func JoinPaths(elem ...string) string +func JoinSubPaths(basePath string, elem ...string) string +func SlashPath(path string) string +func UnixPath(path string) string +func ToAbsPath(p string) string // source at fsutil/info.go -func Dir(fpath string) string -func PathName(fpath string) string -func Name(fpath string) string -func FileExt(fpath string) string -func Extname(fpath string) string -func Suffix(fpath string) string -func Expand(pathStr string) string -func ExpandPath(pathStr string) string -func ResolvePath(pathStr string) string -func SplitPath(pathStr string) (dir, name string) +func DirPath(fpath string) string +func Dir(fpath string) string +func PathName(fpath string) string +func Name(fpath string) string +func FileExt(fpath string) string +func Extname(fpath string) string +func Suffix(fpath string) string +func Expand(pathStr string) string +func ExpandPath(pathStr string) string +func ResolvePath(pathStr string) string +func SplitPath(pathStr string) (dir, name string) // source at fsutil/info_nonwin.go -func Realpath(pathStr string) string +func Realpath(pathStr string) string +// source at fsutil/mime.go +func DetectMime(path string) string +func MimeType(path string) (mime string) +func ReaderMimeType(r io.Reader) (mime string) // source at fsutil/operate.go -func Mkdir(dirPath string, perm os.FileMode) error -func MkDirs(perm os.FileMode, dirPaths ...string) error -func MkSubDirs(perm os.FileMode, parentDir string, subDirs ...string) error -func MkParentDir(fpath string) error -func OpenFile(filepath string, flag int, perm os.FileMode) (*os.File, error) -func MustOpenFile(filepath string, flag int, perm os.FileMode) *os.File -func QuickOpenFile(filepath string, fileFlag ...int) (*os.File, error) -func OpenAppendFile(filepath string, filePerm ...os.FileMode) (*os.File, error) -func OpenTruncFile(filepath string, filePerm ...os.FileMode) (*os.File, error) -func OpenReadFile(filepath string) (*os.File, error) -func CreateFile(fpath string, filePerm, dirPerm os.FileMode, fileFlag ...int) (*os.File, error) -func MustCreateFile(filePath string, filePerm, dirPerm os.FileMode) *os.File -func Remove(fPath string) error -func MustRemove(fPath string) -func QuietRemove(fPath string) -func RmIfExist(fPath string) error -func DeleteIfExist(fPath string) error -func RmFileIfExist(fPath string) error -func DeleteIfFileExist(fPath string) error -func RemoveSub(dirPath string, fns ...FilterFunc) error -func Unzip(archive, targetDir string) (err error) +func Mkdir(dirPath string, perm os.FileMode) error +func MkDirs(perm os.FileMode, dirPaths ...string) error +func MkSubDirs(perm os.FileMode, parentDir string, subDirs ...string) error +func MkParentDir(fpath string) error +func NewOpenOption(optFns ...OpenOptionFunc) *OpenOption +func OpenOptOrNew(opt *OpenOption) *OpenOption +func WithFlag(flag int) OpenOptionFunc +func WithPerm(perm os.FileMode) OpenOptionFunc +func OpenFile(filePath string, flag int, perm os.FileMode) (*os.File, error) +func MustOpenFile(filePath string, flag int, perm os.FileMode) *os.File +func QuickOpenFile(filepath string, fileFlag ...int) (*os.File, error) +func OpenAppendFile(filepath string, filePerm ...os.FileMode) (*os.File, error) +func OpenTruncFile(filepath string, filePerm ...os.FileMode) (*os.File, error) +func OpenReadFile(filepath string) (*os.File, error) +func CreateFile(fpath string, filePerm, dirPerm os.FileMode, fileFlag ...int) (*os.File, error) +func MustCreateFile(filePath string, filePerm, dirPerm os.FileMode) *os.File +func Remove(fPath string) error +func MustRemove(fPath string) +func QuietRemove(fPath string) +func SafeRemoveAll(path string) +func RmIfExist(fPath string) error +func DeleteIfExist(fPath string) error +func RmFileIfExist(fPath string) error +func DeleteIfFileExist(fPath string) error +func RemoveSub(dirPath string, fns ...FilterFunc) error +func Unzip(archive, targetDir string) (err error) // source at fsutil/opread.go -func NewIOReader(in any) (r io.Reader, err error) -func DiscardReader(src io.Reader) -func ReadFile(filePath string) []byte -func MustReadFile(filePath string) []byte -func ReadReader(r io.Reader) []byte -func MustReadReader(r io.Reader) []byte -func ReadString(in any) string -func ReadStringOrErr(in any) (string, error) -func ReadAll(in any) []byte -func GetContents(in any) []byte -func ReadOrErr(in any) ([]byte, error) -func ReadExistFile(filePath string) []byte -func TextScanner(in any) *scanner.Scanner -func LineScanner(in any) *bufio.Scanner +func NewIOReader(in any) (r io.Reader, err error) +func DiscardReader(src io.Reader) +func ReadFile(filePath string) []byte +func MustReadFile(filePath string) []byte +func ReadReader(r io.Reader) []byte +func MustReadReader(r io.Reader) []byte +func ReadString(in any) string +func ReadStringOrErr(in any) (string, error) +func ReadAll(in any) []byte +func GetContents(in any) []byte +func MustRead(in any) []byte +func ReadOrErr(in any) ([]byte, error) +func ReadExistFile(filePath string) []byte +func TextScanner(in any) *scanner.Scanner +func LineScanner(in any) *bufio.Scanner // source at fsutil/opwrite.go -func PutContents(filePath string, data any, fileFlag ...int) (int, error) -func WriteFile(filePath string, data any, perm os.FileMode, fileFlag ...int) error -func WriteOSFile(f *os.File, data any) (n int, err error) -func CopyFile(srcPath, dstPath string) error -func MustCopyFile(srcPath, dstPath string) +func OSTempFile(pattern string) (*os.File, error) +func TempFile(dir, pattern string) (*os.File, error) +func OSTempDir(pattern string) (string, error) +func TempDir(dir, pattern string) (string, error) +func MustSave(filePath string, data any, optFns ...OpenOptionFunc) +func SaveFile(filePath string, data any, optFns ...OpenOptionFunc) error +func PutContents(filePath string, data any, fileFlag ...int) (int, error) +func WriteFile(filePath string, data any, perm os.FileMode, fileFlag ...int) error +func WriteOSFile(f *os.File, data any) (n int, err error) +func CopyFile(srcPath, dstPath string) error +func MustCopyFile(srcPath, dstPath string) +func UpdateContents(filePath string, handleFn func(bs []byte) []byte) error ``` #### FsUtil Usage @@ -779,27 +821,54 @@ func main() { ``` +### Go Info + +> Package `github.com/gookit/goutil/goinfo` + +```go +// source at goinfo/gofunc.go +func FuncName(fn any) string +func CutFuncName(fullFcName string) (pkgPath, shortFnName string) +func PkgName(fullFcName string) string +func GoodFuncName(name string) bool +// source at goinfo/goinfo.go +func GoVersion() string +func ParseGoVersion(line string) (*GoInfo, error) +func OsGoInfo() (*GoInfo, error) +// source at goinfo/stack.go +func GetCallStacks(all bool) []byte +func GetCallerInfo(skip int) string +func SimpleCallersInfo(skip, num int) []string +func GetCallersInfo(skip, max int) []string +``` + ### JSON Utils > Package `github.com/gookit/goutil/jsonutil` ```go +// source at jsonutil/encoding.go +func MustString(v any) string +func Encode(v any) ([]byte, error) +func EncodePretty(v any) ([]byte, error) +func EncodeString(v any) (string, error) +func EncodeToWriter(v any, w io.Writer) error +func EncodeUnescapeHTML(v any) ([]byte, error) +func Decode(bts []byte, ptr any) error +func DecodeString(str string, ptr any) error +func DecodeReader(r io.Reader, ptr any) error // source at jsonutil/jsonutil.go -func WriteFile(filePath string, data any) error -func WritePretty(filePath string, data any) error -func ReadFile(filePath string, v any) error -func Pretty(v any) (string, error) -func Encode(v any) ([]byte, error) -func EncodePretty(v any) ([]byte, error) -func EncodeToWriter(v any, w io.Writer) error -func EncodeUnescapeHTML(v any) ([]byte, error) -func Decode(bts []byte, ptr any) error -func DecodeString(str string, ptr any) error -func DecodeReader(r io.Reader, ptr any) error -func Mapping(src, dst any) error -func IsJSON(s string) bool -func IsJSONFast(s string) bool -func StripComments(src string) string +func WriteFile(filePath string, data any) error +func WritePretty(filePath string, data any) error +func ReadFile(filePath string, v any) error +func Pretty(v any) (string, error) +func MustPretty(v any) string +func Mapping(src, dst any) error +func IsJSON(s string) bool +func IsJSONFast(s string) bool +func IsArray(s string) bool +func IsObject(s string) bool +func StripComments(src string) string ``` ### Map @@ -808,43 +877,44 @@ func StripComments(src string) string ```go // source at maputil/check.go -func HasKey(mp, key any) (ok bool) -func HasOneKey(mp any, keys ...any) (ok bool, key any) -func HasAllKeys(mp any, keys ...any) (ok bool, noKey any) +func HasKey(mp, key any) (ok bool) +func HasOneKey(mp any, keys ...any) (ok bool, key any) +func HasAllKeys(mp any, keys ...any) (ok bool, noKey any) // source at maputil/convert.go -func KeyToLower(src map[string]string) map[string]string -func ToStringMap(src map[string]any) map[string]string -func CombineToSMap(keys, values []string) SMap -func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V -func ToAnyMap(mp any) map[string]any -func TryAnyMap(mp any) (map[string]any, error) -func HTTPQueryString(data map[string]any) string -func StringsMapToAnyMap(ssMp map[string][]string) map[string]any -func ToString(mp map[string]any) string -func ToString2(mp any) string -func FormatIndent(mp any, indent string) string -func Flatten(mp map[string]any) map[string]any -func FlatWithFunc(mp map[string]any, fn reflects.FlatFunc) +func KeyToLower(src map[string]string) map[string]string +func ToStringMap(src map[string]any) map[string]string +func CombineToSMap(keys, values []string) SMap +func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V +func ToAnyMap(mp any) map[string]any +func TryAnyMap(mp any) (map[string]any, error) +func HTTPQueryString(data map[string]any) string +func StringsMapToAnyMap(ssMp map[string][]string) map[string]any +func ToString(mp map[string]any) string +func ToString2(mp any) string +func FormatIndent(mp any, indent string) string +func Flatten(mp map[string]any) map[string]any +func FlatWithFunc(mp map[string]any, fn reflects.FlatFunc) // source at maputil/format.go -func NewFormatter(mp any) *MapFormatter +func NewFormatter(mp any) *MapFormatter // source at maputil/get.go -func DeepGet(mp map[string]any, path string) (val any) -func QuietGet(mp map[string]any, path string) (val any) -func GetByPath(path string, mp map[string]any) (val any, ok bool) -func GetByPathKeys(mp map[string]any, keys []string) (val any, ok bool) -func Keys(mp any) (keys []string) -func Values(mp any) (values []any) -func EachAnyMap(mp any, fn func(key string, val any)) +func DeepGet(mp map[string]any, path string) (val any) +func QuietGet(mp map[string]any, path string) (val any) +func GetFromAny(path string, data any) (val any, ok bool) +func GetByPath(path string, mp map[string]any) (val any, ok bool) +func GetByPathKeys(mp map[string]any, keys []string) (val any, ok bool) +func Keys(mp any) (keys []string) +func Values(mp any) (values []any) +func EachAnyMap(mp any, fn func(key string, val any)) // source at maputil/maputil.go -func SimpleMerge(src, dst map[string]any) map[string]any -func DeepMerge(src, dst map[string]any, deep int) map[string]any -func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string -func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string -func MakeByPath(path string, val any) (mp map[string]any) -func MakeByKeys(keys []string, val any) (mp map[string]any) +func SimpleMerge(src, dst map[string]any) map[string]any +func DeepMerge(src, dst map[string]any, deep int) map[string]any +func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string +func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string +func MakeByPath(path string, val any) (mp map[string]any) +func MakeByKeys(keys []string, val any) (mp map[string]any) // source at maputil/setval.go -func SetByPath(mp *map[string]any, path string, val any) error -func SetByKeys(mp *map[string]any, keys []string, val any) (err error) +func SetByPath(mp *map[string]any, path string, val any) error +func SetByKeys(mp *map[string]any, keys []string, val any) (err error) ``` ### Math/Number @@ -853,68 +923,94 @@ func SetByKeys(mp *map[string]any, keys []string, val any) (err error) ```go // source at mathutil/check.go -func Compare(srcVal, dstVal any, op string) (ok bool) -func CompInt[T comdef.Xint](srcVal, dstVal T, op string) (ok bool) -func CompInt64(srcVal, dstVal int64, op string) bool -func CompFloat[T comdef.Float](srcVal, dstVal T, op string) (ok bool) -func CompValue[T comdef.XintOrFloat](srcVal, dstVal T, op string) (ok bool) -func InRange[T comdef.IntOrFloat](val, min, max T) bool -func OutRange[T comdef.IntOrFloat](val, min, max T) bool -func InUintRange[T comdef.Uint](val, min, max T) bool +func IsNumeric(c byte) bool +func Compare(first, second any, op string) bool +func CompInt[T comdef.Xint](first, second T, op string) (ok bool) +func CompInt64(first, second int64, op string) bool +func CompFloat[T comdef.Float](first, second T, op string) (ok bool) +func CompValue[T comdef.XintOrFloat](first, second T, op string) (ok bool) +func InRange[T comdef.IntOrFloat](val, min, max T) bool +func OutRange[T comdef.IntOrFloat](val, min, max T) bool +func InUintRange[T comdef.Uint](val, min, max T) bool +// source at mathutil/compare.go +func Min[T comdef.XintOrFloat](x, y T) T +func Max[T comdef.XintOrFloat](x, y T) T +func SwapMin[T comdef.XintOrFloat](x, y T) (T, T) +func SwapMax[T comdef.XintOrFloat](x, y T) (T, T) +func MaxInt(x, y int) int +func SwapMaxInt(x, y int) (int, int) +func MaxI64(x, y int64) int64 +func SwapMaxI64(x, y int64) (int64, int64) +func MaxFloat(x, y float64) float64 // source at mathutil/convert.go -func Int(in any) (int, error) -func QuietInt(in any) int -func MustInt(in any) int -func IntOrPanic(in any) int -func IntOrErr(in any) (iVal int, err error) -func ToInt(in any) (iVal int, err error) -func StrInt(s string) int -func Uint(in any) (uint64, error) -func QuietUint(in any) uint64 -func MustUint(in any) uint64 -func UintOrErr(in any) (uint64, error) -func ToUint(in any) (u64 uint64, err error) -func Int64(in any) (int64, error) -func SafeInt64(in any) int64 -func QuietInt64(in any) int64 -func MustInt64(in any) int64 -func Int64OrErr(in any) (int64, error) -func ToInt64(in any) (i64 int64, err error) -func QuietFloat(in any) float64 -func FloatOrPanic(in any) float64 -func MustFloat(in any) float64 -func Float(in any) (float64, error) -func FloatOrErr(in any) (float64, error) -func ToFloat(in any) (f64 float64, err error) -func StringOrPanic(val any) string -func MustString(val any) string -func ToString(val any) (string, error) -func StringOrErr(val any) (string, error) -func QuietString(val any) string -func String(val any) string -func TryToString(val any, defaultAsErr bool) (str string, err error) +func Int(in any) (int, error) +func SafeInt(in any) int +func QuietInt(in any) int +func MustInt(in any) int +func IntOrPanic(in any) int +func IntOrDefault(in any, defVal int) int +func IntOr(in any, defVal int) int +func IntOrErr(in any) (iVal int, err error) +func ToInt(in any) (iVal int, err error) +func ToIntWithFunc(in any, usrFn ToIntFunc) (iVal int, err error) +func StrInt(s string) int +func StrIntOr(s string, defVal int) int +func Uint(in any) (uint64, error) +func SafeUint(in any) uint64 +func QuietUint(in any) uint64 +func MustUint(in any) uint64 +func UintOrDefault(in any, defVal uint64) uint64 +func UintOr(in any, defVal uint64) uint64 +func UintOrErr(in any) (uint64, error) +func ToUint(in any) (u64 uint64, err error) +func ToUintWithFunc(in any, usrFn ToUintFunc) (u64 uint64, err error) +func Int64(in any) (int64, error) +func SafeInt64(in any) int64 +func QuietInt64(in any) int64 +func MustInt64(in any) int64 +func Int64OrDefault(in any, defVal int64) int64 +func Int64Or(in any, defVal int64) int64 +func Int64OrErr(in any) (int64, error) +func ToInt64(in any) (i64 int64, err error) +func ToInt64WithFunc(in any, usrFn ToInt64Func) (i64 int64, err error) +func QuietFloat(in any) float64 +func SafeFloat(in any) float64 +func FloatOrPanic(in any) float64 +func MustFloat(in any) float64 +func FloatOrDefault(in any, defVal float64) float64 +func FloatOr(in any, defVal float64) float64 +func Float(in any) (float64, error) +func FloatOrErr(in any) (float64, error) +func ToFloat(in any) (f64 float64, err error) +func ToFloatWithFunc(in any, usrFn ToFloatFunc) (f64 float64, err error) +func MustString(val any) string +func StringOrPanic(val any) string +func StringOrDefault(val any, defVal string) string +func StringOr(val any, defVal string) string +func ToString(val any) (string, error) +func StringOrErr(val any) (string, error) +func QuietString(val any) string +func String(val any) string +func SafeString(val any) string +func TryToString(val any, defaultAsErr bool) (str string, err error) +func ToStringWithFunc(val any, usrFn comdef.ToStringFunc) (str string, err error) +func Percent(val, total int) float64 +func ElapsedTime(startTime time.Time) string +// source at mathutil/format.go +func DataSize(size uint64) string +func HowLongAgo(sec int64) string // source at mathutil/mathutil.go -func Min[T comdef.XintOrFloat](x, y T) T -func Max[T comdef.XintOrFloat](x, y T) T -func SwapMin[T comdef.XintOrFloat](x, y T) (T, T) -func SwapMax[T comdef.XintOrFloat](x, y T) (T, T) -func MaxInt(x, y int) int -func SwapMaxInt(x, y int) (int, int) -func MaxI64(x, y int64) int64 -func SwapMaxI64(x, y int64) (int64, int64) -func MaxFloat(x, y float64) float64 -func OrElse[T comdef.XintOrFloat](in, nv T) T -// source at mathutil/number.go -func IsNumeric(c byte) bool -func Percent(val, total int) float64 -func ElapsedTime(startTime time.Time) string -func DataSize(size uint64) string -func HowLongAgo(sec int64) string +func OrElse[T comdef.XintOrFloat](val, defVal T) T +func ZeroOr[T comdef.XintOrFloat](val, defVal T) T +func LessOr[T comdef.XintOrFloat](val, max, devVal T) T +func LteOr[T comdef.XintOrFloat](val, max, devVal T) T +func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T +func GteOr[T comdef.XintOrFloat](val, min, defVal T) T // source at mathutil/random.go -func RandomInt(min, max int) int -func RandInt(min, max int) int -func RandIntWithSeed(min, max int, seed int64) int -func RandomIntWithSeed(min, max int, seed int64) int +func RandomInt(min, max int) int +func RandInt(min, max int) int +func RandIntWithSeed(min, max int, seed int64) int +func RandomIntWithSeed(min, max int, seed int64) int ``` ### Reflects @@ -923,45 +1019,63 @@ func RandomIntWithSeed(min, max int, seed int64) int ```go // source at reflects/check.go -func HasChild(v reflect.Value) bool -func IsArrayOrSlice(k reflect.Kind) bool -func IsSimpleKind(k reflect.Kind) bool -func IsAnyInt(k reflect.Kind) bool -func IsIntx(k reflect.Kind) bool -func IsUintX(k reflect.Kind) bool -func IsNil(v reflect.Value) bool -func IsFunc(val any) bool -func IsEqual(src, dst any) bool -func IsEmpty(v reflect.Value) bool -func IsEmptyValue(v reflect.Value) bool +func HasChild(v reflect.Value) bool +func IsArrayOrSlice(k reflect.Kind) bool +func IsSimpleKind(k reflect.Kind) bool +func IsAnyInt(k reflect.Kind) bool +func IsIntLike(k reflect.Kind) bool +func IsIntx(k reflect.Kind) bool +func IsUintX(k reflect.Kind) bool +func IsNil(v reflect.Value) bool +func CanBeNil(typ reflect.Type) bool +func IsFunc(val any) bool +func IsEqual(src, dst any) bool +func IsEmpty(v reflect.Value) bool +func IsEmptyReal(v reflect.Value) bool // source at reflects/conv.go -func BaseTypeVal(v reflect.Value) (value any, err error) -func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error) -func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) -func ConvSlice(oldSlRv reflect.Value, newElemTyp reflect.Type) (rv reflect.Value, err error) -func String(rv reflect.Value) string -func ToString(rv reflect.Value) (str string, err error) -func ValToString(rv reflect.Value, defaultAsErr bool) (str string, err error) +func BaseTypeVal(v reflect.Value) (value any, err error) +func ToBaseVal(v reflect.Value) (value any, err error) +func ConvToType(val any, typ reflect.Type) (rv reflect.Value, err error) +func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error) +func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) +func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error) +func ConvSlice(oldSlRv reflect.Value, newElemTyp reflect.Type) (rv reflect.Value, err error) +func String(rv reflect.Value) string +func ToString(rv reflect.Value) (str string, err error) +func ValToString(rv reflect.Value, defaultAsErr bool) (str string, err error) +// source at reflects/func.go +func NewFunc(fn any) *FuncX +func Call2(fn reflect.Value, args []reflect.Value) (reflect.Value, error) +func Call(fn reflect.Value, args []reflect.Value, opt *CallOpt) ([]reflect.Value, error) +func SafeCall2(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) +func SafeCall(fun reflect.Value, args []reflect.Value) (ret []reflect.Value, err error) +// source at reflects/map.go +func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) +func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) +func FlatMap(rv reflect.Value, fn FlatFunc) +// source at reflects/slice.go +func MakeSliceByElem(elTyp reflect.Type, len, cap int) reflect.Value +func FlatSlice(sl reflect.Value, depth int) reflect.Value // source at reflects/type.go -func ToBaseKind(kind reflect.Kind) BKind -func ToBKind(kind reflect.Kind) BKind -func TypeOf(v any) Type +func ToBaseKind(kind reflect.Kind) BKind +func ToBKind(kind reflect.Kind) BKind +func TypeOf(v any) Type // source at reflects/util.go -func Elem(v reflect.Value) reflect.Value -func Indirect(v reflect.Value) reflect.Value -func Len(v reflect.Value) int -func SliceSubKind(typ reflect.Type) reflect.Kind -func SliceElemKind(typ reflect.Type) reflect.Kind -func UnexportedValue(rv reflect.Value) any -func SetUnexportedValue(rv reflect.Value, value any) -func SetValue(rv reflect.Value, val any) error -func SetRValue(rv, val reflect.Value) -func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) -func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) -func FlatMap(rv reflect.Value, fn FlatFunc) +func Elem(v reflect.Value) reflect.Value +func Indirect(v reflect.Value) reflect.Value +func UnwrapAny(v reflect.Value) reflect.Value +func TypeReal(t reflect.Type) reflect.Type +func TypeElem(t reflect.Type) reflect.Type +func Len(v reflect.Value) int +func SliceSubKind(typ reflect.Type) reflect.Kind +func SliceElemKind(typ reflect.Type) reflect.Kind +func UnexportedValue(rv reflect.Value) any +func SetUnexportedValue(rv reflect.Value, value any) +func SetValue(rv reflect.Value, val any) error +func SetRValue(rv, val reflect.Value) // source at reflects/value.go -func Wrap(rv reflect.Value) Value -func ValueOf(v any) Value +func Wrap(rv reflect.Value) Value +func ValueOf(v any) Value ``` ### Stdio @@ -970,65 +1084,24 @@ func ValueOf(v any) Value ```go // source at stdio/ioutil.go -func QuietFprint(w io.Writer, a ...any) -func QuietFprintf(w io.Writer, tpl string, vs ...any) -func QuietFprintln(w io.Writer, a ...any) -func QuietWriteString(w io.Writer, ss ...string) +func QuietFprint(w io.Writer, a ...any) +func QuietFprintf(w io.Writer, tpl string, vs ...any) +func QuietFprintln(w io.Writer, a ...any) +func QuietWriteString(w io.Writer, ss ...string) // source at stdio/stdio.go -func DiscardReader(src io.Reader) -func ReadString(r io.Reader) string -func MustReadReader(r io.Reader) []byte -func NewIOReader(in any) io.Reader -func NewScanner(in any) *bufio.Scanner -func WriteByte(b byte) -func WriteBytes(bs []byte) -func WritelnBytes(bs []byte) -func WriteString(s string) -func Writeln(s string) +func DiscardReader(src io.Reader) +func ReadString(r io.Reader) string +func MustReadReader(r io.Reader) []byte +func NewIOReader(in any) io.Reader +func NewScanner(in any) *bufio.Scanner +func WriteByte(b byte) +func WriteBytes(bs []byte) +func WritelnBytes(bs []byte) +func WriteString(s string) +func Writeln(s string) // source at stdio/writer.go -func NewWriteWrapper(w io.Writer) *WriteWrapper -``` - -### Standard - -> Package `github.com/gookit/goutil/stdutil` - -```go -// source at stdutil/chan.go -func WaitCloseSignals(closer io.Closer) error -func Go(f func() error) error -func SignalHandler(ctx context.Context, signals ...os.Signal) (execute func() error, interrupt func(error)) -// source at stdutil/check.go -func IsNil(v any) bool -func IsEmpty(v any) bool -func IsFunc(val any) bool -func IsEqual(src, dst any) bool -func Contains(data, elem any) bool -func IsContains(data, elem any) bool -func CheckContains(data, elem any) (valid, found bool) -func ValueIsEmpty(v reflect.Value) bool -func ValueLen(v reflect.Value) int -// source at stdutil/conv.go -func ToString(v any) string -func MustString(v any) string -func TryString(v any) (string, error) -func BaseTypeVal(val any) (value any, err error) -func BaseTypeVal2(v reflect.Value) (value any, err error) -// source at stdutil/gofunc.go -func FuncName(fn any) string -func CutFuncName(fullFcName string) (pkgPath, shortFnName string) -func PkgName(fullFcName string) string -// source at stdutil/stack.go -func GetCallStacks(all bool) []byte -func GetCallerInfo(skip int) string -func SimpleCallersInfo(skip, num int) []string -func GetCallersInfo(skip, max int) []string -// source at stdutil/stdutil.go -func DiscardE(_ error) -func PanicIfErr(err error) -func PanicIf(err error) -func Panicf(format string, v ...any) -func GoVersion() string +func WrapW(w io.Writer) *WriteWrapper +func NewWriteWrapper(w io.Writer) *WriteWrapper ``` ### Structs @@ -1037,49 +1110,49 @@ func GoVersion() string ```go // source at structs/alias.go -func NewAliases(checker func(alias string)) *Aliases +func NewAliases(checker func(alias string)) *Aliases // source at structs/convert.go -func ToMap(st any, optFns ...MapOptFunc) map[string]any -func MustToMap(st any, optFns ...MapOptFunc) map[string]any -func TryToMap(st any, optFns ...MapOptFunc) (map[string]any, error) -func ToSMap(st any, optFns ...MapOptFunc) map[string]string -func TryToSMap(st any, optFns ...MapOptFunc) (map[string]string, error) -func MustToSMap(st any, optFns ...MapOptFunc) map[string]string -func ToString(st any, optFns ...MapOptFunc) string -func WithMapTagName(tagName string) MapOptFunc -func MergeAnonymous(opt *MapOptions) -func ExportPrivate(opt *MapOptions) -func StructToMap(st any, optFns ...MapOptFunc) (map[string]any, error) +func ToMap(st any, optFns ...MapOptFunc) map[string]any +func MustToMap(st any, optFns ...MapOptFunc) map[string]any +func TryToMap(st any, optFns ...MapOptFunc) (map[string]any, error) +func ToSMap(st any, optFns ...MapOptFunc) map[string]string +func TryToSMap(st any, optFns ...MapOptFunc) (map[string]string, error) +func MustToSMap(st any, optFns ...MapOptFunc) map[string]string +func ToString(st any, optFns ...MapOptFunc) string +func WithMapTagName(tagName string) MapOptFunc +func MergeAnonymous(opt *MapOptions) +func ExportPrivate(opt *MapOptions) +func StructToMap(st any, optFns ...MapOptFunc) (map[string]any, error) // source at structs/copy.go -func MapStruct(srcSt, dstSt any) +func MapStruct(srcSt, dstSt any) // source at structs/data.go -func NewLiteData(data map[string]any) *Data -func NewData() *Data -func NewOrderedMap(len int) *OrderedMap +func NewLiteData(data map[string]any) *Data +func NewData() *Data +func NewOrderedData(cap int) *OrderedData // source at structs/init.go -func Init(ptr any, optFns ...InitOptFunc) error -func InitDefaults(ptr any, optFns ...InitOptFunc) error +func Init(ptr any, optFns ...InitOptFunc) error +func InitDefaults(ptr any, optFns ...InitOptFunc) error // source at structs/structs.go -func IsExported(name string) bool -func IsUnexported(name string) bool +func IsExported(name string) bool +func IsUnexported(name string) bool // source at structs/tags.go -func ParseTags(st any, tagNames []string) (map[string]maputil.SMap, error) -func ParseReflectTags(rt reflect.Type, tagNames []string) (map[string]maputil.SMap, error) -func NewTagParser(tagNames ...string) *TagParser -func ParseTagValueDefault(field, tagVal string) (mp maputil.SMap, err error) -func ParseTagValueQuick(tagVal string, defines []string) maputil.SMap -func ParseTagValueDefine(sep string, defines []string) TagValFunc -func ParseTagValueNamed(field, tagVal string, keys ...string) (mp maputil.SMap, err error) +func ParseTags(st any, tagNames []string) (map[string]maputil.SMap, error) +func ParseReflectTags(rt reflect.Type, tagNames []string) (map[string]maputil.SMap, error) +func NewTagParser(tagNames ...string) *TagParser +func ParseTagValueDefault(field, tagVal string) (mp maputil.SMap, err error) +func ParseTagValueQuick(tagVal string, defines []string) maputil.SMap +func ParseTagValueDefine(sep string, defines []string) TagValFunc +func ParseTagValueNamed(field, tagVal string, keys ...string) (mp maputil.SMap, err error) // source at structs/value.go -func NewValue(val any) *Value +func NewValue(val any) *Value // source at structs/wrapper.go -func Wrap(src any) *Wrapper -func NewWrapper(src any) *Wrapper -func WrapValue(rv reflect.Value) *Wrapper +func Wrap(src any) *Wrapper +func NewWrapper(src any) *Wrapper +func WrapValue(rv reflect.Value) *Wrapper // source at structs/writer.go -func NewWriter(ptr any) *Wrapper -func WithParseDefault(opt *SetOptions) -func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error +func NewWriter(ptr any) *Wrapper +func WithParseDefault(opt *SetOptions) +func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error ``` ### Strings @@ -1088,219 +1161,267 @@ func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error ```go // source at strutil/bytes.go -func NewBuffer() *Buffer -func NewByteChanPool(maxSize, width, capWidth int) *ByteChanPool +func NewBuffer() *Buffer +func NewByteChanPool(maxSize, width, capWidth int) *ByteChanPool // source at strutil/check.go -func IsNumChar(c byte) bool -func IsNumeric(s string) bool -func IsAlphabet(char uint8) bool -func IsAlphaNum(c uint8) bool -func StrPos(s, sub string) int -func BytePos(s string, bt byte) int -func IEqual(s1, s2 string) bool -func NoCaseEq(s, t string) bool -func IContains(s, sub string) bool -func ContainsByte(s string, c byte) bool -func ContainsOne(s string, subs []string) bool -func HasOneSub(s string, subs []string) bool -func ContainsAll(s string, subs []string) bool -func HasAllSubs(s string, subs []string) bool -func IsStartsOf(s string, prefixes []string) bool -func HasOnePrefix(s string, prefixes []string) bool -func HasPrefix(s string, prefix string) bool -func IsStartOf(s, prefix string) bool -func HasSuffix(s string, suffix string) bool -func IsEndOf(s, suffix string) bool -func HasOneSuffix(s string, suffixes []string) bool -func IsValidUtf8(s string) bool -func IsSpace(c byte) bool -func IsEmpty(s string) bool -func IsBlank(s string) bool -func IsNotBlank(s string) bool -func IsBlankBytes(bs []byte) bool -func IsSymbol(r rune) bool -func HasEmpty(ss ...string) bool -func IsAllEmpty(ss ...string) bool -func IsVersion(s string) bool -func Compare(s1, s2, op string) bool -func VersionCompare(v1, v2, op string) bool -func SimpleMatch(s string, keywords []string) bool -func QuickMatch(pattern, s string) bool -func PathMatch(pattern, s string) bool -func GlobMatch(pattern, s string) bool -func LikeMatch(pattern, s string) bool -func MatchNodePath(pattern, s string, sep string) bool +func IsNumChar(c byte) bool +func IsNumeric(s string) bool +func IsAlphabet(char uint8) bool +func IsAlphaNum(c uint8) bool +func StrPos(s, sub string) int +func BytePos(s string, bt byte) int +func IEqual(s1, s2 string) bool +func NoCaseEq(s, t string) bool +func IContains(s, sub string) bool +func ContainsByte(s string, c byte) bool +func ContainsOne(s string, subs []string) bool +func HasOneSub(s string, subs []string) bool +func ContainsAll(s string, subs []string) bool +func HasAllSubs(s string, subs []string) bool +func IsStartsOf(s string, prefixes []string) bool +func HasOnePrefix(s string, prefixes []string) bool +func HasPrefix(s string, prefix string) bool +func IsStartOf(s, prefix string) bool +func HasSuffix(s string, suffix string) bool +func IsEndOf(s, suffix string) bool +func HasOneSuffix(s string, suffixes []string) bool +func IsValidUtf8(s string) bool +func IsSpace(c byte) bool +func IsEmpty(s string) bool +func IsBlank(s string) bool +func IsNotBlank(s string) bool +func IsBlankBytes(bs []byte) bool +func IsSymbol(r rune) bool +func HasEmpty(ss ...string) bool +func IsAllEmpty(ss ...string) bool +func IsVersion(s string) bool +func Compare(s1, s2, op string) bool +func VersionCompare(v1, v2, op string) bool +func SimpleMatch(s string, keywords []string) bool +func QuickMatch(pattern, s string) bool +func PathMatch(pattern, s string) bool +func GlobMatch(pattern, s string) bool +func LikeMatch(pattern, s string) bool +func MatchNodePath(pattern, s string, sep string) bool +// source at strutil/convbase.go +func Base10Conv(src string, to int) string +func BaseConv(src string, from, to int) string +func BaseConvByTpl(src string, fromBase, toBase string) string // source at strutil/convert.go -func Quote(s string) string -func Unquote(s string) string -func Join(sep string, ss ...string) string -func JoinList(sep string, ss []string) string -func JoinAny(sep string, parts ...any) string -func Implode(sep string, ss ...string) string -func String(val any) (string, error) -func ToString(val any) (string, error) -func QuietString(in any) string -func SafeString(in any) string -func MustString(in any) string -func StringOrErr(val any) (string, error) -func AnyToString(val any, defaultAsErr bool) (str string, err error) -func Byte2str(b []byte) string -func Byte2string(b []byte) string -func ToBytes(s string) (b []byte) -func ToBool(s string) (bool, error) -func QuietBool(s string) bool -func MustBool(s string) bool -func Bool(s string) (bool, error) -func Int(s string) (int, error) -func ToInt(s string) (int, error) -func Int2(s string) int -func QuietInt(s string) int -func MustInt(s string) int -func IntOrPanic(s string) int -func Int64(s string) int64 -func QuietInt64(s string) int64 -func ToInt64(s string) (int64, error) -func Int64OrErr(s string) (int64, error) -func MustInt64(s string) int64 -func Int64OrPanic(s string) int64 -func Ints(s string, sep ...string) []int -func ToInts(s string, sep ...string) ([]int, error) -func ToIntSlice(s string, sep ...string) (ints []int, err error) -func ToArray(s string, sep ...string) []string -func Strings(s string, sep ...string) []string -func ToStrings(s string, sep ...string) []string -func ToSlice(s string, sep ...string) []string -func ToOSArgs(s string) []string -func ToDuration(s string) (time.Duration, error) -// source at strutil/crypto.go -func Md5(src any) string -func MD5(src any) string -func GenMd5(src any) string -func Md5Bytes(src any) []byte -func HashPasswd(pwd, key string) string -func VerifyPasswd(pwdMAC, pwd, key string) bool +func Quote(s string) string +func Unquote(s string) string +func Join(sep string, ss ...string) string +func JoinList(sep string, ss []string) string +func JoinAny(sep string, parts ...any) string +func Implode(sep string, ss ...string) string +func String(val any) (string, error) +func ToString(val any) (string, error) +func StringOrErr(val any) (string, error) +func QuietString(val any) string +func SafeString(in any) string +func StringOrPanic(val any) string +func MustString(val any) string +func StringOrDefault(val any, defVal string) string +func StringOr(val any, defVal string) string +func AnyToString(val any, defaultAsErr bool) (s string, err error) +func ToStringWithFunc(val any, fbFn comdef.ToStringFunc) (str string, err error) +func ToBool(s string) (bool, error) +func QuietBool(s string) bool +func SafeBool(s string) bool +func MustBool(s string) bool +func Bool(s string) (bool, error) +func Int(s string) (int, error) +func ToInt(s string) (int, error) +func IntOrDefault(s string, defVal int) int +func IntOr(s string, defVal int) int +func SafeInt(s string) int +func QuietInt(s string) int +func MustInt(s string) int +func IntOrPanic(s string) int +func Int64(s string) int64 +func SafeInt64(s string) int64 +func QuietInt64(s string) int64 +func ToInt64(s string) (int64, error) +func Int64OrDefault(s string, defVal int64) int64 +func Int64Or(s string, defVal int64) int64 +func Int64OrErr(s string) (int64, error) +func MustInt64(s string) int64 +func Int64OrPanic(s string) int64 +func Uint(s string) uint64 +func SafeUint(s string) uint64 +func ToUint(s string) (uint64, error) +func UintOrErr(s string) (uint64, error) +func MustUint(s string) uint64 +func UintOrPanic(s string) uint64 +func UintOrDefault(s string, defVal uint64) uint64 +func UintOr(s string, defVal uint64) uint64 +func Byte2str(b []byte) string +func Byte2string(b []byte) string +func ToBytes(s string) (b []byte) +func Ints(s string, sep ...string) []int +func ToInts(s string, sep ...string) ([]int, error) +func ToIntSlice(s string, sep ...string) (ints []int, err error) +func ToArray(s string, sep ...string) []string +func Strings(s string, sep ...string) []string +func ToStrings(s string, sep ...string) []string +func ToSlice(s string, sep ...string) []string +func ToOSArgs(s string) []string +func ToDuration(s string) (time.Duration, error) // source at strutil/encode.go -func EscapeJS(s string) string -func EscapeHTML(s string) string -func AddSlashes(s string) string -func StripSlashes(s string) string -func URLEncode(s string) string -func URLDecode(s string) string -func B32Encode(str string) string -func B32Decode(str string) string -func B64Encode(str string) string -func B64EncodeBytes(src []byte) []byte -func B64Decode(str string) string -func B64DecodeBytes(str string) []byte -func Encoding(base int, typ BaseType) BaseEncoder +func EscapeJS(s string) string +func EscapeHTML(s string) string +func AddSlashes(s string) string +func StripSlashes(s string) string +func URLEncode(s string) string +func URLDecode(s string) string +func B32Encode(str string) string +func B32Decode(str string) string +func B64Encode(str string) string +func B64EncodeBytes(src []byte) []byte +func B64Decode(str string) string +func B64DecodeBytes(str []byte) []byte // source at strutil/ext.go -func NewComparator(src, dst string) *SimilarComparator -func Similarity(s, t string, rate float32) (float32, bool) +func NewComparator(src, dst string) *SimilarComparator +func Similarity(s, t string, rate float32) (float32, bool) // source at strutil/filter.go -func Trim(s string, cutSet ...string) string -func Ltrim(s string, cutSet ...string) string -func LTrim(s string, cutSet ...string) string -func TrimLeft(s string, cutSet ...string) string -func Rtrim(s string, cutSet ...string) string -func RTrim(s string, cutSet ...string) string -func TrimRight(s string, cutSet ...string) string -func FilterEmail(s string) string -func Filter(ss []string, fls ...comdef.StringMatchFunc) []string +func Trim(s string, cutSet ...string) string +func Ltrim(s string, cutSet ...string) string +func LTrim(s string, cutSet ...string) string +func TrimLeft(s string, cutSet ...string) string +func Rtrim(s string, cutSet ...string) string +func RTrim(s string, cutSet ...string) string +func TrimRight(s string, cutSet ...string) string +func FilterEmail(s string) string +func Filter(ss []string, fls ...comdef.StringMatchFunc) []string // source at strutil/format.go -func Title(s string) string -func Lower(s string) string -func Lowercase(s string) string -func Upper(s string) string -func Uppercase(s string) string -func UpperWord(s string) string -func LowerFirst(s string) string -func UpperFirst(s string) string -func SnakeCase(s string, sep ...string) string -func Camel(s string, sep ...string) string -func CamelCase(s string, sep ...string) string -func Indent(s, prefix string) string -func IndentBytes(b, prefix []byte) []byte -// source at strutil/id.go -func MicroTimeID() string -func MicroTimeHexID() string -func DatetimeNo(prefix string) string +func Title(s string) string +func Lower(s string) string +func Lowercase(s string) string +func Upper(s string) string +func Uppercase(s string) string +func UpperWord(s string) string +func LowerFirst(s string) string +func UpperFirst(s string) string +func SnakeCase(s string, sep ...string) string +func Camel(s string, sep ...string) string +func CamelCase(s string, sep ...string) string +func Indent(s, prefix string) string +func IndentBytes(b, prefix []byte) []byte +// source at strutil/gensn.go +func MicroTimeID() string +func MicroTimeHexID() string +func MTimeHexID() string +func MTimeBaseID(toBase int) string +func DatetimeNo(prefix string) string +func DateSN(prefix string) string +func DateSNV2(prefix string, extBase ...int) string +// source at strutil/hash.go +func Md5(src any) string +func MD5(src any) string +func GenMd5(src any) string +func Md5Bytes(src any) []byte +func ShortMd5(src any) string +func HashPasswd(pwd, key string) string +func VerifyPasswd(pwdMAC, pwd, key string) bool // source at strutil/padding.go -func Padding(s, pad string, length int, pos PosFlag) string -func PadLeft(s, pad string, length int) string -func PadRight(s, pad string, length int) string -func Resize(s string, length int, align PosFlag) string -func PadChars[T byte | rune](cs []T, pad T, length int, pos PosFlag) []T -func PadBytes(bs []byte, pad byte, length int, pos PosFlag) []byte -func PadBytesLeft(bs []byte, pad byte, length int) []byte -func PadBytesRight(bs []byte, pad byte, length int) []byte -func PadRunes(rs []rune, pad rune, length int, pos PosFlag) []rune -func PadRunesLeft(rs []rune, pad rune, length int) []rune -func PadRunesRight(rs []rune, pad rune, length int) []rune -func Repeat(s string, times int) string -func RepeatRune(char rune, times int) []rune -func RepeatBytes(char byte, times int) []byte -func RepeatChars[T byte | rune](char T, times int) []T +func Padding(s, pad string, length int, pos PosFlag) string +func PadLeft(s, pad string, length int) string +func PadRight(s, pad string, length int) string +func Resize(s string, length int, align PosFlag) string +func PadChars[T byte | rune](cs []T, pad T, length int, pos PosFlag) []T +func PadBytes(bs []byte, pad byte, length int, pos PosFlag) []byte +func PadBytesLeft(bs []byte, pad byte, length int) []byte +func PadBytesRight(bs []byte, pad byte, length int) []byte +func PadRunes(rs []rune, pad rune, length int, pos PosFlag) []rune +func PadRunesLeft(rs []rune, pad rune, length int) []rune +func PadRunesRight(rs []rune, pad rune, length int) []rune +func Repeat(s string, times int) string +func RepeatRune(char rune, times int) []rune +func RepeatBytes(char byte, times int) []byte +func RepeatChars[T byte | rune](char T, times int) []T // source at strutil/parse.go -func MustToTime(s string, layouts ...string) time.Time -func ToTime(s string, layouts ...string) (t time.Time, err error) -func ParseSizeRange(expr string, opt *ParseSizeOpt) (min, max uint64, err error) -func SafeByteSize(sizeStr string) uint64 -func ToByteSize(sizeStr string) (uint64, error) +func MustToTime(s string, layouts ...string) time.Time +func ToTime(s string, layouts ...string) (t time.Time, err error) +func ParseSizeRange(expr string, opt *ParseSizeOpt) (min, max uint64, err error) +func SafeByteSize(sizeStr string) uint64 +func ToByteSize(sizeStr string) (uint64, error) // source at strutil/random.go -func RandomChars(ln int) string -func RandomCharsV2(ln int) string -func RandomCharsV3(ln int) string -func RandomBytes(length int) ([]byte, error) -func RandomString(length int) (string, error) -func RandWithTpl(n int, letters string) string +func RandomChars(ln int) string +func RandomCharsV2(ln int) string +func RandomCharsV3(ln int) string +func RandWithTpl(n int, letters string) string +func RandomString(length int) (string, error) +func RandomBytes(length int) ([]byte, error) // source at strutil/runes.go -func RuneIsWord(c rune) bool -func RuneIsLower(c rune) bool -func RuneIsUpper(c rune) bool -func RunePos(s string, ru rune) int -func IsSpaceRune(r rune) bool -func Utf8Len(s string) int -func Utf8len(s string) int -func RuneCount(s string) int -func RuneWidth(r rune) int -func TextWidth(s string) int -func Utf8Width(s string) int -func RunesWidth(rs []rune) (w int) -func Truncate(s string, w int, tail string) string -func TextTruncate(s string, w int, tail string) string -func Utf8Truncate(s string, w int, tail string) string -func TextSplit(s string, w int) []string -func Utf8Split(s string, w int) []string -func TextWrap(s string, w int) string -func WidthWrap(s string, w int) string -func WordWrap(s string, w int) string +func RuneIsWord(c rune) bool +func RuneIsLower(c rune) bool +func RuneIsUpper(c rune) bool +func RunePos(s string, ru rune) int +func IsSpaceRune(r rune) bool +func Utf8Len(s string) int +func Utf8len(s string) int +func RuneCount(s string) int +func RuneWidth(r rune) int +func TextWidth(s string) int +func Utf8Width(s string) int +func RunesWidth(rs []rune) (w int) +func Truncate(s string, w int, tail string) string +func TextTruncate(s string, w int, tail string) string +func Utf8Truncate(s string, w int, tail string) string +func TextSplit(s string, w int) []string +func Utf8Split(s string, w int) []string +func TextWrap(s string, w int) string +func WidthWrap(s string, w int) string +func WordWrap(s string, w int) string // source at strutil/split.go -func Cut(s, sep string) (before string, after string, found bool) -func QuietCut(s, sep string) (before string, after string) -func MustCut(s, sep string) (before string, after string) -func TrimCut(s, sep string) (string, string) -func SplitKV(s, sep string) (string, string) -func SplitValid(s, sep string) (ss []string) -func Split(s, sep string) (ss []string) -func SplitNValid(s, sep string, n int) (ss []string) -func SplitN(s, sep string, n int) (ss []string) -func SplitTrimmed(s, sep string) (ss []string) -func SplitNTrimmed(s, sep string, n int) (ss []string) -func Substr(s string, pos, length int) string -func SplitInlineComment(val string, strict ...bool) (string, string) -func FirstLine(output string) string +func BeforeFirst(s, sep string) string +func AfterFirst(s, sep string) string +func BeforeLast(s, sep string) string +func AfterLast(s, sep string) string +func Cut(s, sep string) (before string, after string, found bool) +func QuietCut(s, sep string) (before string, after string) +func MustCut(s, sep string) (before string, after string) +func TrimCut(s, sep string) (string, string) +func SplitKV(s, sep string) (string, string) +func SplitValid(s, sep string) (ss []string) +func Split(s, sep string) (ss []string) +func SplitNValid(s, sep string, n int) (ss []string) +func SplitN(s, sep string, n int) (ss []string) +func SplitTrimmed(s, sep string) (ss []string) +func SplitNTrimmed(s, sep string, n int) (ss []string) +func Substr(s string, pos, length int) string +func SplitInlineComment(val string, strict ...bool) (string, string) +func FirstLine(output string) string // source at strutil/strutil.go -func OrCond(cond bool, s1, s2 string) string -func OrElse(s, orVal string) string -func OrHandle(s string, fn func(s string) string) string -func Valid(ss ...string) string -func Replaces(str string, pairs map[string]string) string -func NewReplacer(pairs map[string]string) *strings.Replacer -func PrettyJSON(v any) (string, error) -func RenderTemplate(input string, data any, fns template.FuncMap, isFile ...bool) string -func RenderText(input string, data any, fns template.FuncMap, isFile ...bool) string -func WrapTag(s, tag string) string -func SubstrCount(s string, substr string, params ...uint64) (int, error) +func OrCond(cond bool, s1, s2 string) string +func BlankOr(val, defVal string) string +func ZeroOr[T ~string](val, defVal T) T +func ErrorOr(s string, err error, defVal string) string +func OrElse(s, orVal string) string +func OrHandle(s string, fn comdef.StringHandleFunc) string +func Valid(ss ...string) string +func Replaces(str string, pairs map[string]string) string +func NewReplacer(pairs map[string]string) *strings.Replacer +func PrettyJSON(v any) (string, error) +func RenderTemplate(input string, data any, fns template.FuncMap, isFile ...bool) string +func RenderText(input string, data any, fns template.FuncMap, isFile ...bool) string +func WrapTag(s, tag string) string +func SubstrCount(s, substr string, params ...uint64) (int, error) +``` + +### Syncs + +> Package `github.com/gookit/goutil/syncs` + +```go +// source at syncs/chan.go +func WaitCloseSignals(onClose func(sig os.Signal)) +func Go(f func() error) error +// source at syncs/group.go +func NewCtxErrGroup(ctx context.Context, limit ...int) (*ErrGroup, context.Context) +func NewErrGroup(limit ...int) *ErrGroup +// source at syncs/signal.go +func SignalHandler(ctx context.Context, signals ...os.Signal) (execute func() error, interrupt func(error)) ``` ### System Utils @@ -1309,68 +1430,69 @@ func SubstrCount(s string, substr string, params ...uint64) (int, error) ```go // source at sysutil/exec.go -func NewCmd(bin string, args ...string) *cmdr.Cmd -func FlushExec(bin string, args ...string) error -func QuickExec(cmdLine string, workDir ...string) (string, error) -func ExecLine(cmdLine string, workDir ...string) (string, error) -func ExecCmd(binName string, args []string, workDir ...string) (string, error) -func ShellExec(cmdLine string, shells ...string) (string, error) +func NewCmd(bin string, args ...string) *cmdr.Cmd +func FlushExec(bin string, args ...string) error +func QuickExec(cmdLine string, workDir ...string) (string, error) +func ExecLine(cmdLine string, workDir ...string) (string, error) +func ExecCmd(binName string, args []string, workDir ...string) (string, error) +func ShellExec(cmdLine string, shells ...string) (string, error) // source at sysutil/stack.go -func CallersInfos(skip, num int, filters ...func(file string, fc *runtime.Func) bool) []*CallerInfo +func CallersInfos(skip, num int, filters ...func(file string, fc *runtime.Func) bool) []*CallerInfo // source at sysutil/sysenv.go -func IsMSys() bool -func IsConsole(out io.Writer) bool -func IsTerminal(fd uintptr) bool -func StdIsTerminal() bool -func Hostname() string -func CurrentShell(onlyName bool) (path string) -func HasShellEnv(shell string) bool -func IsShellSpecialVar(c uint8) bool -func FindExecutable(binName string) (string, error) -func Executable(binName string) (string, error) -func HasExecutable(binName string) bool -func Getenv(name string, def ...string) string -func Environ() map[string]string -func EnvMapWith(newEnv map[string]string) map[string]string -func EnvPaths() []string -func SearchPath(keywords string, limit int) []string +func IsMSys() bool +func IsConsole(out io.Writer) bool +func IsTerminal(fd uintptr) bool +func StdIsTerminal() bool +func Hostname() string +func CurrentShell(onlyName bool) (path string) +func HasShellEnv(shell string) bool +func IsShellSpecialVar(c uint8) bool +func FindExecutable(binName string) (string, error) +func Executable(binName string) (string, error) +func HasExecutable(binName string) bool +func Getenv(name string, def ...string) string +func Environ() map[string]string +func EnvMapWith(newEnv map[string]string) map[string]string +func EnvPaths() []string +func SearchPath(keywords string, limit int) []string // source at sysutil/sysgo.go -func GoVersion() string -func ParseGoVersion(line string) (*GoInfo, error) -func OsGoInfo() (*GoInfo, error) +func GoVersion() string +func ParseGoVersion(line string) (*GoInfo, error) +func OsGoInfo() (*GoInfo, error) // source at sysutil/sysutil.go -func Workdir() string -func BinDir() string -func BinName() string -func BinFile() string -func Open(fileOrURL string) error -func OpenBrowser(fileOrURL string) error -func OpenFile(path string) error +func Workdir() string +func BinDir() string +func BinName() string +func BinFile() string +func Open(fileOrURL string) error +func OpenBrowser(fileOrURL string) error +func OpenFile(path string) error // source at sysutil/sysutil_nonwin.go -func Kill(pid int, signal syscall.Signal) error -func ProcessExists(pid int) bool +func Kill(pid int, signal syscall.Signal) error +func ProcessExists(pid int) bool // source at sysutil/sysutil_unix.go -func IsWin() bool -func IsWindows() bool -func IsMac() bool -func IsDarwin() bool -func IsLinux() bool -func OpenURL(URL string) error +func IsWin() bool +func IsWindows() bool +func IsMac() bool +func IsDarwin() bool +func IsLinux() bool +func OpenURL(URL string) error // source at sysutil/user.go -func MustFindUser(uname string) *user.User -func LoginUser() *user.User -func CurrentUser() *user.User -func UHomeDir() string -func UserHomeDir() string -func HomeDir() string -func UserDir(subPath string) string -func UserCacheDir(subPath string) string -func UserConfigDir(subPath string) string -func ExpandPath(path string) string -func ExpandHome(path string) string +func MustFindUser(uname string) *user.User +func LoginUser() *user.User +func CurrentUser() *user.User +func UHomeDir() string +func UserHomeDir() string +func HomeDir() string +func UserDir(subPath string) string +func UserCacheDir(subPath string) string +func UserConfigDir(subPath string) string +func ExpandPath(path string) string +func ExpandHome(path string) string // source at sysutil/user_nonwin.go -func ChangeUserByName(newUname string) (err error) -func ChangeUserUidGid(newUID int, newGid int) (err error) +func ChangeUserByName(newUname string) error +func ChangeUserUidGid(newUID int, newGid int) error +func ChangeUserUIDGid(newUID int, newGid int) (err error) ``` ### Testing Utils @@ -1379,34 +1501,37 @@ func ChangeUserUidGid(newUID int, newGid int) (err error) ```go // source at testutil/buffer.go -func NewBuffer() *byteutil.Buffer +func NewBuffer() *byteutil.Buffer // source at testutil/envmock.go -func MockEnvValue(key, val string, fn func(nv string)) -func MockEnvValues(kvMap map[string]string, fn func()) -func MockOsEnvByText(envText string, fn func()) -func MockOsEnv(mp map[string]string, fn func()) -func ClearOSEnv() -func RevertOSEnv() -func MockCleanOsEnv(mp map[string]string, fn func()) -// source at testutil/fsmock.go -func NewDirEnt(fpath string, isDir ...bool) *fakeobj.DirEntry +func MockEnvValue(key, val string, fn func(nv string)) +func MockEnvValues(kvMap map[string]string, fn func()) +func MockOsEnvByText(envText string, fn func()) +func MockOsEnv(mp map[string]string, fn func()) +func ClearOSEnv() +func RevertOSEnv() +func MockCleanOsEnv(mp map[string]string, fn func()) // source at testutil/httpmock.go -func NewHttpRequest(method, path string, data *MD) *http.Request -func MockRequest(h http.Handler, method, path string, data *MD) *httptest.ResponseRecorder -func TestMain(m *testing.M) -func NewEchoServer() *httptest.Server -func BuildEchoReply(r *http.Request) *EchoReply -func ParseRespToReply(w *http.Response) *EchoReply -func ParseBodyToReply(bd io.ReadCloser) *EchoReply +func NewHttpRequest(method, path string, data *MD) *http.Request +func NewHTTPRequest(method, path string, data *MD) *http.Request +func MockRequest(h http.Handler, method, path string, data *MD) *httptest.ResponseRecorder +func TestMain(m *testing.M) +func NewEchoServer() *httptest.Server +func BuildEchoReply(r *http.Request) *EchoReply +func ParseRespToReply(w *http.Response) *EchoReply +func ParseBodyToReply(bd io.ReadCloser) *EchoReply // source at testutil/testutil.go -func DiscardStdout() error -func ReadOutput() (s string) -func RewriteStdout() -func RestoreStdout(printData ...bool) (s string) -func RewriteStderr() -func RestoreStderr(printData ...bool) (s string) +func DiscardStdout() error +func ReadOutput() (s string) +func RewriteStdout() +func RestoreStdout(printData ...bool) (s string) +func RewriteStderr() +func RestoreStderr(printData ...bool) (s string) +func SetTimeLocal(tl *time.Location) +func SetTimeLocalUTC() +func RestoreTimeLocal() // source at testutil/writer.go -func NewTestWriter() *TestWriter +func NewTestWriter() *TestWriter +func NewDirEnt(fpath string, isDir ...bool) *fakeobj.DirEntry ``` ### Timex @@ -1415,57 +1540,65 @@ func NewTestWriter() *TestWriter Provides an enhanced time.Time implementation, and add more commonly used functional methods. ```go +// source at timex/check.go +func IsDuration(s string) bool +func InRange(dst, start, end time.Time) bool +// source at timex/conv.go +func Elapsed(start, end time.Time) string +func ElapsedNow(start time.Time) string +func FromNow(t time.Time) string +func FromNowWith(u time.Time, tms []TimeMessage) string +func HowLongAgo(diffSec int64) string +func HowLongAgo2(diffSec int64, tms []TimeMessage) string +func ToTime(s string, layouts ...string) (time.Time, error) +func ToDur(s string) (time.Duration, error) +func ToDuration(s string) (time.Duration, error) +func TryToTime(s string, bt time.Time) (time.Time, error) +func ParseRange(expr string, opt *ParseRangeOpt) (start, end time.Time, err error) // source at timex/gotime.go -func SetLocalByName(tzName string) error -func NowAddDay(day int) time.Time -func NowAddHour(hour int) time.Time -func NowAddMinutes(minutes int) time.Time -func NowAddSec(seconds int) time.Time -func NowAddSeconds(seconds int) time.Time -func NowHourStart() time.Time -func NowHourEnd() time.Time -func AddDay(t time.Time, day int) time.Time -func AddHour(t time.Time, hour int) time.Time -func AddMinutes(t time.Time, minutes int) time.Time -func AddSeconds(t time.Time, seconds int) time.Time -func AddSec(t time.Time, seconds int) time.Time -func HourStart(t time.Time) time.Time -func HourEnd(t time.Time) time.Time -func DayStart(t time.Time) time.Time -func DayEnd(t time.Time) time.Time -func TodayStart() time.Time -func TodayEnd() time.Time +func SetLocalByName(tzName string) error +func NowAddDay(day int) time.Time +func NowAddHour(hour int) time.Time +func NowAddMinutes(minutes int) time.Time +func NowAddSec(seconds int) time.Time +func NowAddSeconds(seconds int) time.Time +func NowHourStart() time.Time +func NowHourEnd() time.Time +func AddDay(t time.Time, day int) time.Time +func AddHour(t time.Time, hour int) time.Time +func AddMinutes(t time.Time, minutes int) time.Time +func AddSeconds(t time.Time, seconds int) time.Time +func AddSec(t time.Time, seconds int) time.Time +func HourStart(t time.Time) time.Time +func HourEnd(t time.Time) time.Time +func DayStart(t time.Time) time.Time +func DayEnd(t time.Time) time.Time +func TodayStart() time.Time +func TodayEnd() time.Time // source at timex/template.go -func ToLayout(template string) string +func ToLayout(template string) string // source at timex/timex.go -func Now() *Time -func New(t time.Time) *Time -func Wrap(t time.Time) *Time -func FromTime(t time.Time) *Time -func Local() *Time -func FromUnix(sec int64) *Time -func FromDate(s string, template ...string) (*Time, error) -func FromString(s string, layouts ...string) (*Time, error) -func LocalByName(tzName string) *Time +func Now() *Time +func New(t time.Time) *Time +func Wrap(t time.Time) *Time +func FromTime(t time.Time) *Time +func Local() *Time +func FromUnix(sec int64) *Time +func FromDate(s string, template ...string) (*Time, error) +func FromString(s string, layouts ...string) (*Time, error) +func LocalByName(tzName string) *Time // source at timex/util.go -func NowUnix() int64 -func Format(t time.Time) string -func FormatBy(t time.Time, layout string) string -func Date(t time.Time, template ...string) string -func Datetime(t time.Time, template ...string) string -func DateFormat(t time.Time, template string) string -func FormatByTpl(t time.Time, template string) string -func FormatUnix(sec int64, layout ...string) string -func FormatUnixBy(sec int64, layout string) string -func FormatUnixByTpl(sec int64, template ...string) string -func HowLongAgo(sec int64) string -func ToTime(s string, layouts ...string) (time.Time, error) -func ToDur(s string) (time.Duration, error) -func ToDuration(s string) (time.Duration, error) -func IsDuration(s string) bool -func TryToTime(s string, bt time.Time) (time.Time, error) -func InRange(dst, start, end time.Time) bool -func ParseRange(expr string, opt *ParseRangeOpt) (start, end time.Time, err error) +func NowUnix() int64 +func NowDate(template ...string) string +func Format(t time.Time) string +func FormatBy(t time.Time, layout string) string +func Date(t time.Time, template ...string) string +func Datetime(t time.Time, template ...string) string +func DateFormat(t time.Time, template string) string +func FormatByTpl(t time.Time, template string) string +func FormatUnix(sec int64, layout ...string) string +func FormatUnixBy(sec int64, layout string) string +func FormatUnixByTpl(sec int64, template ...string) string ``` #### Timex Usage diff --git a/vendor/github.com/gookit/goutil/arrutil/arrutil.go b/vendor/github.com/gookit/goutil/arrutil/arrutil.go index dff26561f..583435696 100644 --- a/vendor/github.com/gookit/goutil/arrutil/arrutil.go +++ b/vendor/github.com/gookit/goutil/arrutil/arrutil.go @@ -2,95 +2,9 @@ package arrutil import ( - "strings" - - "github.com/gookit/goutil/comdef" "github.com/gookit/goutil/mathutil" ) -// Reverse string slice [site user info 0] -> [0 info user site] -func Reverse(ss []string) { - ln := len(ss) - for i := 0; i < ln/2; i++ { - li := ln - i - 1 - ss[i], ss[li] = ss[li], ss[i] - } -} - -// StringsRemove a value form a string slice -func StringsRemove(ss []string, s string) []string { - ns := make([]string, 0, len(ss)) - for _, v := range ss { - if v != s { - ns = append(ns, v) - } - } - return ns -} - -// StringsFilter given strings, default will filter emtpy string. -// -// Usage: -// -// // output: [a, b] -// ss := arrutil.StringsFilter([]string{"a", "", "b", ""}) -func StringsFilter(ss []string, filter ...func(s string) bool) []string { - var fn func(s string) bool - if len(filter) > 0 && filter[0] != nil { - fn = filter[0] - } else { - fn = func(s string) bool { - return s != "" - } - } - - ns := make([]string, 0, len(ss)) - for _, s := range ss { - if fn(s) { - ns = append(ns, s) - } - } - return ns -} - -// StringsMap handle each string item, map to new strings -func StringsMap(ss []string, mapFn func(s string) string) []string { - ns := make([]string, 0, len(ss)) - for _, s := range ss { - ns = append(ns, mapFn(s)) - } - return ns -} - -// TrimStrings trim string slice item. -// -// Usage: -// -// // output: [a, b, c] -// ss := arrutil.TrimStrings([]string{",a", "b.", ",.c,"}, ",.") -func TrimStrings(ss []string, cutSet ...string) []string { - cutSetLn := len(cutSet) - hasCutSet := cutSetLn > 0 && cutSet[0] != "" - - var trimSet string - if hasCutSet { - trimSet = cutSet[0] - } - if cutSetLn > 1 { - trimSet = strings.Join(cutSet, "") - } - - ns := make([]string, 0, len(ss)) - for _, str := range ss { - if hasCutSet { - ns = append(ns, strings.Trim(str, trimSet)) - } else { - ns = append(ns, strings.TrimSpace(str)) - } - } - return ns -} - // GetRandomOne get random element from an array/slice func GetRandomOne[T any](arr []T) T { return RandomOne(arr) } @@ -102,31 +16,3 @@ func RandomOne[T any](arr []T) T { } panic("cannot get value from nil or empty slice") } - -// Unique value in the given slice data. -func Unique[T ~string | comdef.XintOrFloat](list []T) []T { - if len(list) < 2 { - return list - } - - valMap := make(map[T]struct{}, len(list)) - uniArr := make([]T, 0, len(list)) - - for _, t := range list { - if _, ok := valMap[t]; !ok { - valMap[t] = struct{}{} - uniArr = append(uniArr, t) - } - } - return uniArr -} - -// IndexOf value in given slice. -func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int { - for i, v := range list { - if v == val { - return i - } - } - return -1 -} diff --git a/vendor/github.com/gookit/goutil/arrutil/check.go b/vendor/github.com/gookit/goutil/arrutil/check.go index 60117f07c..7a786c1e7 100644 --- a/vendor/github.com/gookit/goutil/arrutil/check.go +++ b/vendor/github.com/gookit/goutil/arrutil/check.go @@ -8,8 +8,18 @@ import ( "github.com/gookit/goutil/mathutil" ) -// IntsHas check the []int contains the given value -func IntsHas(ints []int, val int) bool { +// SliceHas check the slice contains the given value +func SliceHas[T comdef.ScalarType](slice []T, val T) bool { + for _, ele := range slice { + if ele == val { + return true + } + } + return false +} + +// IntsHas check the []comdef.Integer contains the given value +func IntsHas[T comdef.Integer](ints []T, val T) bool { for _, ele := range ints { if ele == val { return true @@ -28,11 +38,8 @@ func Int64sHas(ints []int64, val int64) bool { return false } -// InStrings alias of StringsHas() -func InStrings(elem string, ss []string) bool { return StringsHas(ss, elem) } - // StringsHas check the []string contains the given element -func StringsHas(ss []string, val string) bool { +func StringsHas[T ~string](ss []T, val T) bool { for _, ele := range ss { if ele == val { return true @@ -41,6 +48,11 @@ func StringsHas(ss []string, val string) bool { return false } +// InStrings check elem in the ss. alias of StringsHas() +func InStrings[T ~string](elem T, ss []T) bool { + return StringsHas(ss, elem) +} + // NotIn check the given value whether not in the list func NotIn[T comdef.ScalarType](value T, list []T) bool { return !In(value, list) diff --git a/vendor/github.com/gookit/goutil/arrutil/collection.go b/vendor/github.com/gookit/goutil/arrutil/collection.go index ac556bfa3..4b06ddab3 100644 --- a/vendor/github.com/gookit/goutil/arrutil/collection.go +++ b/vendor/github.com/gookit/goutil/arrutil/collection.go @@ -2,97 +2,72 @@ package arrutil import ( "errors" - "reflect" + + "github.com/gookit/goutil/comdef" + "github.com/gookit/goutil/reflects" ) // ErrElementNotFound is the error returned when the element is not found. -const ErrElementNotFound = "element not found" +var ErrElementNotFound = errors.New("element not found") // Comparer Function to compare two elements. -type Comparer func(a, b any) int +type Comparer[T any] func(a, b T) int + +// type Comparer func(a, b any) int // Predicate Function to predicate a struct/value satisfies a condition. -type Predicate func(a any) bool +type Predicate[T any] func(v T) bool -var ( - // StringEqualsComparer Comparer for string. It will compare the string by their value. - // returns: 0 if equal, -1 if a != b - StringEqualsComparer Comparer = func(a, b any) int { - typeOfA := reflect.TypeOf(a) - if typeOfA.Kind() == reflect.Ptr { - typeOfA = typeOfA.Elem() - } - - typeOfB := reflect.TypeOf(b) - if typeOfB.Kind() == reflect.Ptr { - typeOfB = typeOfB.Elem() - } - - if typeOfA != typeOfB { - return -1 - } - - strA := "" - strB := "" - - if val, ok := a.(string); ok { - strA = val - } else if val, ok := a.(*string); ok { - strA = *val - } else { - return -1 - } - - if val, ok := b.(string); ok { - strB = val - } else if val, ok := b.(*string); ok { - strB = *val - } else { - return -1 - } - - if strA == strB { - return 0 - } - return -1 - } - - // ReferenceEqualsComparer Comparer for strcut ptr. It will compare the struct by their ptr addr. - // returns: 0 if equal, -1 if a != b - ReferenceEqualsComparer Comparer = func(a, b any) int { - if a == b { - return 0 - } - return -1 - } - - // ElemTypeEqualsComparer Comparer for struct/value. It will compare the struct by their element type (reflect.Type.Elem()). - // returns: 0 if same type, -1 if not. - ElemTypeEqualsComparer Comparer = func(a, b any) int { - at := reflect.TypeOf(a) - bt := reflect.TypeOf(b) - if at.Kind() == reflect.Ptr { - at = at.Elem() - } - - if bt.Kind() == reflect.Ptr { - bt = bt.Elem() - } - - if at == bt { - return 0 - } - return -1 - } -) - -// TwowaySearch Find specialized element in a slice forward and backward in the same time, should be more quickly. +// StringEqualsComparer Comparer for string. It will compare the string by their value. // -// data: the slice to search in. MUST BE A SLICE. -// item: the element to search. -// fn: the comparer function. -// return: the index of the element, or -1 if not found. -func TwowaySearch(data any, item any, fn Comparer) (int, error) { +// returns: 0 if equal, -1 if a != b +func StringEqualsComparer(a, b string) int { + if a == b { + return 0 + } + return -1 +} + +// ValueEqualsComparer Comparer for comdef.Compared type. It will compare by their value. +// +// returns: 0 if equal, -1 if a != b +func ValueEqualsComparer[T comdef.Compared](a, b T) int { + if a == b { + return 0 + } + return -1 +} + +// ReflectEqualsComparer Comparer for struct ptr. It will compare by reflect.Value +// +// returns: 0 if equal, -1 if a != b +func ReflectEqualsComparer[T any](a, b T) int { + if reflects.IsEqual(a, b) { + return 0 + } + return -1 +} + +// ElemTypeEqualsComparer Comparer for struct/value. It will compare the struct by their element type. +// +// returns: 0 if same type, -1 if not. +func ElemTypeEqualsComparer[T any](a, b T) int { + at := reflects.TypeOf(a).SafeElem() + bt := reflects.TypeOf(b).SafeElem() + + if at == bt { + return 0 + } + return -1 +} + +// TwowaySearch find specialized element in a slice forward and backward in the same time, should be more quickly. +// +// - data: the slice to search in. MUST BE A SLICE. +// - item: the element to search. +// - fn: the comparer function. +// - return: the index of the element, or -1 if not found. +func TwowaySearch[T any](data []T, item T, fn Comparer[T]) (int, error) { if data == nil { return -1, errors.New("collections.TwowaySearch: data is nil") } @@ -100,35 +75,19 @@ func TwowaySearch(data any, item any, fn Comparer) (int, error) { return -1, errors.New("collections.TwowaySearch: fn is nil") } - dataType := reflect.TypeOf(data) - if dataType.Kind() != reflect.Slice { - return -1, errors.New("collections.TwowaySearch: data is not a slice") - } - - dataVal := reflect.ValueOf(data) - if dataVal.Len() == 0 { + if len(data) == 0 { return -1, errors.New("collections.TwowaySearch: data is empty") } - itemType := dataType.Elem() - if itemType.Kind() == reflect.Ptr { - itemType = itemType.Elem() - } - - if itemType != dataVal.Index(0).Type() { - return -1, errors.New("collections.TwowaySearch: item type is not the same as data type") - } forward := 0 - backward := dataVal.Len() - 1 + backward := len(data) - 1 for forward <= backward { - forwardVal := dataVal.Index(forward).Interface() - if fn(forwardVal, item) == 0 { + if fn(data[forward], item) == 0 { return forward, nil } - backwardVal := dataVal.Index(backward).Interface() - if fn(backwardVal, item) == 0 { + if fn(data[backward], item) == 0 { return backward, nil } @@ -136,55 +95,44 @@ func TwowaySearch(data any, item any, fn Comparer) (int, error) { backward-- } - return -1, errors.New(ErrElementNotFound) -} - -// MakeEmptySlice Create a new slice with the elements of the source that satisfy the predicate. -// -// itemType: the type of the elements in the source. -// returns: the new slice. -func MakeEmptySlice(itemType reflect.Type) any { - ret := reflect.MakeSlice(reflect.SliceOf(itemType), 0, 0).Interface() - return ret + return -1, ErrElementNotFound } // CloneSlice Clone a slice. // // data: the slice to clone. // returns: the cloned slice. -func CloneSlice(data any) any { - typeOfData := reflect.TypeOf(data) - if typeOfData.Kind() != reflect.Slice { - panic("collections.CloneSlice: data must be a slice") - } - return reflect.AppendSlice(reflect.New(reflect.SliceOf(typeOfData.Elem())).Elem(), reflect.ValueOf(data)).Interface() +func CloneSlice[T any](data []T) []T { + nt := make([]T, 0, len(data)) + nt = append(nt, data...) + return nt +} + +// Diff Produces the set difference of two slice according to a comparer function. alias of Differences +func Diff[T any](first, second []T, fn Comparer[T]) []T { + return Differences(first, second, fn) } // Differences Produces the set difference of two slice according to a comparer function. // -// first: the first slice. MUST BE A SLICE. -// second: the second slice. MUST BE A SLICE. -// fn: the comparer function. -// returns: the difference of the two slices. -func Differences[T any](first, second []T, fn Comparer) []T { - typeOfFirst := reflect.TypeOf(first) - if typeOfFirst.Kind() != reflect.Slice { - panic("collections.Excepts: first must be a slice") - } - - typeOfSecond := reflect.TypeOf(second) - if typeOfSecond.Kind() != reflect.Slice { - panic("collections.Excepts: second must be a slice") - } - +// - first: the first slice. MUST BE A SLICE. +// - second: the second slice. MUST BE A SLICE. +// - fn: the comparer function. +// - returns: the difference of the two slices. +// +// Example: +// +// // Output: []string{"c"} +// Differences([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.StringEqualsComparer +func Differences[T any](first, second []T, fn Comparer[T]) []T { firstLen := len(first) if firstLen == 0 { - return CloneSlice(second).([]T) + return CloneSlice(second) } secondLen := len(second) if secondLen == 0 { - return CloneSlice(first).([]T) + return CloneSlice(first) } max := firstLen @@ -214,139 +162,123 @@ func Differences[T any](first, second []T, fn Comparer) []T { // Excepts Produces the set difference of two slice according to a comparer function. // -// first: the first slice. MUST BE A SLICE. -// second: the second slice. MUST BE A SLICE. -// fn: the comparer function. -// returns: the difference of the two slices. -func Excepts(first, second any, fn Comparer) any { - typeOfFirst := reflect.TypeOf(first) - if typeOfFirst.Kind() != reflect.Slice { - panic("collections.Excepts: first must be a slice") +// - first: the first slice. MUST BE A SLICE. +// - second: the second slice. MUST BE A SLICE. +// - fn: the comparer function. +// - returns: the difference of the two slices. +// +// Example: +// +// // Output: []string{"c"} +// Excepts([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.StringEqualsComparer) +func Excepts[T any](first, second []T, fn Comparer[T]) []T { + if len(first) == 0 { + return make([]T, 0) } - valOfFirst := reflect.ValueOf(first) - if valOfFirst.Len() == 0 { - return MakeEmptySlice(typeOfFirst.Elem()) - } - - typeOfSecond := reflect.TypeOf(second) - if typeOfSecond.Kind() != reflect.Slice { - panic("collections.Excepts: second must be a slice") - } - - valOfSecond := reflect.ValueOf(second) - if valOfSecond.Len() == 0 { + if len(second) == 0 { return CloneSlice(first) } - result := reflect.New(reflect.SliceOf(typeOfFirst.Elem())).Elem() - for i := 0; i < valOfFirst.Len(); i++ { - s := valOfFirst.Index(i).Interface() + result := make([]T, 0) + for _, s := range first { if i, _ := TwowaySearch(second, s, fn); i < 0 { - result = reflect.Append(result, reflect.ValueOf(s)) + result = append(result, s) } } - - return result.Interface() + return result } // Intersects Produces to intersect of two slice according to a comparer function. // -// first: the first slice. MUST BE A SLICE. -// second: the second slice. MUST BE A SLICE. -// fn: the comparer function. -// returns: to intersect of the two slices. -func Intersects(first any, second any, fn Comparer) any { - typeOfFirst := reflect.TypeOf(first) - if typeOfFirst.Kind() != reflect.Slice { - panic("collections.Intersects: first must be a slice") - } - valOfFirst := reflect.ValueOf(first) - if valOfFirst.Len() == 0 { - return MakeEmptySlice(typeOfFirst.Elem()) +// - first: the first slice. MUST BE A SLICE. +// - second: the second slice. MUST BE A SLICE. +// - fn: the comparer function. +// - returns: to intersect of the two slices. +// +// Example: +// +// // Output: []string{"a", "b"} +// Intersects([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.ValueEqualsComparer) +func Intersects[T any](first, second []T, fn Comparer[T]) []T { + if len(first) == 0 || len(second) == 0 { + return make([]T, 0) } - typeOfSecond := reflect.TypeOf(second) - if typeOfSecond.Kind() != reflect.Slice { - panic("collections.Intersects: second must be a slice") - } - - valOfSecond := reflect.ValueOf(second) - if valOfSecond.Len() == 0 { - return MakeEmptySlice(typeOfFirst.Elem()) - } - - result := reflect.New(reflect.SliceOf(typeOfFirst.Elem())).Elem() - for i := 0; i < valOfFirst.Len(); i++ { - s := valOfFirst.Index(i).Interface() + result := make([]T, 0) + for _, s := range first { if i, _ := TwowaySearch(second, s, fn); i >= 0 { - result = reflect.Append(result, reflect.ValueOf(s)) + result = append(result, s) } } - - return result.Interface() + return result } // Union Produces the set union of two slice according to a comparer function // -// first: the first slice. MUST BE A SLICE. -// second: the second slice. MUST BE A SLICE. -// fn: the comparer function. -// returns: the union of the two slices. -func Union(first, second any, fn Comparer) any { - excepts := Excepts(second, first, fn) - - typeOfFirst := reflect.TypeOf(first) - if typeOfFirst.Kind() != reflect.Slice { - panic("collections.Intersects: first must be a slice") - } - valOfFirst := reflect.ValueOf(first) - if valOfFirst.Len() == 0 { +// - first: the first slice. MUST BE A SLICE. +// - second: the second slice. MUST BE A SLICE. +// - fn: the comparer function. +// - returns: the union of the two slices. +// +// Example: +// +// // Output: []string{"a", "b", "c"} +// sl := Union([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.ValueEqualsComparer) +func Union[T any](first, second []T, fn Comparer[T]) []T { + if len(first) == 0 { return CloneSlice(second) } - result := reflect.AppendSlice(reflect.New(reflect.SliceOf(typeOfFirst.Elem())).Elem(), valOfFirst) - result = reflect.AppendSlice(result, reflect.ValueOf(excepts)) - return result.Interface() + excepts := Excepts(second, first, fn) + nt := make([]T, 0, len(first)+len(second)) + nt = append(nt, first...) + return append(nt, excepts...) } -// Find Produces the struct/value of a slice according to a predicate function. +// Find Produces the value of a slice according to a predicate function. // -// source: the slice. MUST BE A SLICE. -// fn: the predicate function. -// returns: the struct/value of the slice. -func Find(source any, fn Predicate) (any, error) { - aType := reflect.TypeOf(source) - if aType.Kind() != reflect.Slice { - panic("collections.Find: source must be a slice") +// - source: the slice. MUST BE A SLICE. +// - fn: the predicate function. +// - returns: the struct/value of the slice. +// +// Example: +// +// // Output: "c" +// val := Find([]string{"a", "b", "c"}, func(s string) bool { +// return s == "c" +// }) +func Find[T any](source []T, fn Predicate[T]) (v T, err error) { + err = ErrElementNotFound + if len(source) == 0 { + return } - sourceVal := reflect.ValueOf(source) - if sourceVal.Len() == 0 { - return nil, errors.New(ErrElementNotFound) - } - - for i := 0; i < sourceVal.Len(); i++ { - s := sourceVal.Index(i).Interface() + for _, s := range source { if fn(s) { return s, nil } } - return nil, errors.New(ErrElementNotFound) + return } -// FindOrDefault Produce the struct/value f a slice to a predicate function, +// FindOrDefault Produce the value f a slice to a predicate function, // Produce default value when predicate function not found. // -// source: the slice. MUST BE A SLICE. -// fn: the predicate function. -// defaultValue: the default value. -// returns: the struct/value of the slice. -func FindOrDefault(source any, fn Predicate, defaultValue any) any { +// - source: the slice. MUST BE A SLICE. +// - fn: the predicate function. +// - defaultValue: the default value. +// - returns: the value of the slice. +// +// Example: +// +// // Output: "d" +// val := FindOrDefault([]string{"a", "b", "c"}, func(s string) bool { +// return s == "d" +// }, "d") +func FindOrDefault[T any](source []T, fn Predicate[T], defaultValue T) T { item, err := Find(source, fn) if err != nil { - if err.Error() == ErrElementNotFound { - return defaultValue - } + return defaultValue } return item } @@ -354,53 +286,53 @@ func FindOrDefault(source any, fn Predicate, defaultValue any) any { // TakeWhile Produce the set of a slice according to a predicate function, // Produce empty slice when predicate function not matched. // -// data: the slice. MUST BE A SLICE. -// fn: the predicate function. -// returns: the set of the slice. -func TakeWhile(data any, fn Predicate) any { - aType := reflect.TypeOf(data) - if aType.Kind() != reflect.Slice { - panic("collections.TakeWhile: data must be a slice") +// - data: the slice. MUST BE A SLICE. +// - fn: the predicate function. +// - returns: the set of the slice. +// +// Example: +// +// // Output: []string{"a", "b"} +// sl := TakeWhile([]string{"a", "b", "c"}, func(s string) bool { +// return s != "c" +// }) +func TakeWhile[T any](data []T, fn Predicate[T]) []T { + result := make([]T, 0) + if len(data) == 0 { + return result } - sourceVal := reflect.ValueOf(data) - if sourceVal.Len() == 0 { - return MakeEmptySlice(aType.Elem()) - } - - result := reflect.New(reflect.SliceOf(aType.Elem())).Elem() - for i := 0; i < sourceVal.Len(); i++ { - s := sourceVal.Index(i).Interface() - if fn(s) { - result = reflect.Append(result, reflect.ValueOf(s)) + for _, v := range data { + if fn(v) { + result = append(result, v) } } - return result.Interface() + return result } // ExceptWhile Produce the set of a slice except with a predicate function, // Produce original slice when predicate function not match. // -// data: the slice. MUST BE A SLICE. -// fn: the predicate function. -// returns: the set of the slice. -func ExceptWhile(data any, fn Predicate) any { - aType := reflect.TypeOf(data) - if aType.Kind() != reflect.Slice { - panic("collections.ExceptWhile: data must be a slice") +// - data: the slice. MUST BE A SLICE. +// - fn: the predicate function. +// - returns: the set of the slice. +// +// Example: +// +// // Output: []string{"a", "b"} +// sl := ExceptWhile([]string{"a", "b", "c"}, func(s string) bool { +// return s == "c" +// }) +func ExceptWhile[T any](data []T, fn Predicate[T]) []T { + result := make([]T, 0) + if len(data) == 0 { + return result } - sourceVal := reflect.ValueOf(data) - if sourceVal.Len() == 0 { - return MakeEmptySlice(aType.Elem()) - } - - result := reflect.New(reflect.SliceOf(aType.Elem())).Elem() - for i := 0; i < sourceVal.Len(); i++ { - s := sourceVal.Index(i).Interface() - if !fn(s) { - result = reflect.Append(result, reflect.ValueOf(s)) + for _, v := range data { + if !fn(v) { + result = append(result, v) } } - return result.Interface() + return result } diff --git a/vendor/github.com/gookit/goutil/arrutil/collection_gte118.go b/vendor/github.com/gookit/goutil/arrutil/collection_gte118.go deleted file mode 100644 index fe406caf1..000000000 --- a/vendor/github.com/gookit/goutil/arrutil/collection_gte118.go +++ /dev/null @@ -1,22 +0,0 @@ -package arrutil - -// type MapFn func(obj T) (target V, find bool) - -// Map a list to new list -// -// eg: mapping [object0{},object1{},...] to flatten list [object0.someKey, object1.someKey, ...] -func Map[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V { - flatArr := make([]V, 0, len(list)) - - for _, obj := range list { - if target, ok := mapFn(obj); ok { - flatArr = append(flatArr, target) - } - } - return flatArr -} - -// Column alias of Map func -func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V { - return Map(list, mapFn) -} diff --git a/vendor/github.com/gookit/goutil/arrutil/convert.go b/vendor/github.com/gookit/goutil/arrutil/convert.go index 34dbb3c43..17ce8f6e7 100644 --- a/vendor/github.com/gookit/goutil/arrutil/convert.go +++ b/vendor/github.com/gookit/goutil/arrutil/convert.go @@ -29,6 +29,29 @@ func StringsJoin(sep string, ss ...string) string { return strings.Join(ss, sep) } +// JoinTyped join typed []T slice to string. +// +// Usage: +// +// JoinTyped(",", 1,2,3) // "1,2,3" +// JoinTyped(",", "a","b","c") // "a,b,c" +// JoinTyped[any](",", "a",1,"c") // "a,1,c" +func JoinTyped[T any](sep string, arr ...T) string { + if arr == nil { + return "" + } + + var sb strings.Builder + for i, v := range arr { + if i > 0 { + sb.WriteString(sep) + } + sb.WriteString(strutil.QuietString(v)) + } + + return sb.String() +} + // JoinSlice join []any slice to string. func JoinSlice(sep string, arr ...any) string { if arr == nil { @@ -47,9 +70,27 @@ func JoinSlice(sep string, arr ...any) string { } /************************************************************* - * helper func for slices + * convert func for ints *************************************************************/ +// IntsToString convert []T to string +func IntsToString[T comdef.Integer](ints []T) string { + if len(ints) == 0 { + return "[]" + } + + var sb strings.Builder + sb.WriteByte('[') + for i, v := range ints { + if i > 0 { + sb.WriteByte(',') + } + sb.WriteString(strconv.FormatInt(int64(v), 10)) + } + sb.WriteByte(']') + return sb.String() +} + // ToInt64s convert any(allow: array,slice) to []int64 func ToInt64s(arr any) (ret []int64, err error) { rv := reflect.ValueOf(arr) @@ -84,29 +125,9 @@ func SliceToInt64s(arr []any) []int64 { return i64s } -// StringsAsInts convert and ignore error -func StringsAsInts(ss []string) []int { - ints, _ := StringsTryInts(ss) - return ints -} - -// StringsToInts string slice to int slice -func StringsToInts(ss []string) (ints []int, err error) { - return StringsTryInts(ss) -} - -// StringsTryInts string slice to int slice -func StringsTryInts(ss []string) (ints []int, err error) { - for _, str := range ss { - iVal, err := strconv.Atoi(str) - if err != nil { - return nil, err - } - - ints = append(ints, iVal) - } - return -} +/************************************************************* + * convert func for anys + *************************************************************/ // AnyToSlice convert any(allow: array,slice) to []any func AnyToSlice(sl any) (ls []any, err error) { @@ -136,15 +157,6 @@ func MustToStrings(arr any) []string { return ret } -// StringsToSlice convert []string to []any -func StringsToSlice(ss []string) []any { - args := make([]any, len(ss)) - for i, s := range ss { - args[i] = s - } - return args -} - // ToStrings convert any(allow: array,slice) to []string func ToStrings(arr any) (ret []string, err error) { rv := reflect.ValueOf(arr) @@ -168,16 +180,16 @@ func ToStrings(arr any) (ret []string, err error) { return } -// SliceToStrings convert []any to []string +// SliceToStrings safe convert []any to []string func SliceToStrings(arr []any) []string { return QuietStrings(arr) } -// QuietStrings convert []any to []string +// QuietStrings safe convert []any to []string func QuietStrings(arr []any) []string { ss := make([]string, len(arr)) for i, v := range arr { - ss[i] = strutil.QuietString(v) + ss[i] = strutil.SafeString(v) } return ss } @@ -219,8 +231,8 @@ func AnyToString(arr any) string { // SliceToString convert []any to string func SliceToString(arr ...any) string { return ToString(arr) } -// ToString simple and quickly convert []any to string -func ToString(arr []any) string { +// ToString simple and quickly convert []T to string +func ToString[T any](arr []T) string { // like fmt.Println([]any(nil)) if arr == nil { return "[]" @@ -233,14 +245,14 @@ func ToString(arr []any) string { if i > 0 { sb.WriteByte(',') } - sb.WriteString(strutil.QuietString(v)) + sb.WriteString(strutil.SafeString(v)) } sb.WriteByte(']') return sb.String() } -// CombineToMap combine two slice to map[K]V. +// CombineToMap combine []K and []V slice to map[K]V. // // If keys length is greater than values, the extra keys will be ignored. func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V { diff --git a/vendor/github.com/gookit/goutil/arrutil/enum.go b/vendor/github.com/gookit/goutil/arrutil/enum.go deleted file mode 100644 index a5a70f0ec..000000000 --- a/vendor/github.com/gookit/goutil/arrutil/enum.go +++ /dev/null @@ -1,64 +0,0 @@ -package arrutil - -import ( - "strconv" - "strings" -) - -// Ints type -type Ints []int - -// String to string -func (is Ints) String() string { - ss := make([]string, len(is)) - for i, iv := range is { - ss[i] = strconv.Itoa(iv) - } - return strings.Join(ss, ",") -} - -// Has given element -func (is Ints) Has(i int) bool { - for _, iv := range is { - if i == iv { - return true - } - } - return false -} - -// Strings type -type Strings []string - -// String to string -func (ss Strings) String() string { - return strings.Join(ss, ",") -} - -// Join to string -func (ss Strings) Join(sep string) string { - return strings.Join(ss, sep) -} - -// Has given element -func (ss Strings) Has(sub string) bool { - return ss.Contains(sub) -} - -// Contains given element -func (ss Strings) Contains(sub string) bool { - for _, s := range ss { - if s == sub { - return true - } - } - return false -} - -// First element value. -func (ss Strings) First() string { - if len(ss) > 0 { - return ss[0] - } - return "" -} diff --git a/vendor/github.com/gookit/goutil/arrutil/format.go b/vendor/github.com/gookit/goutil/arrutil/format.go index d00b582a9..5e2f91091 100644 --- a/vendor/github.com/gookit/goutil/arrutil/format.go +++ b/vendor/github.com/gookit/goutil/arrutil/format.go @@ -15,7 +15,7 @@ type ArrFormatter struct { Prefix string // Indent string for format each element Indent string - // ClosePrefix string for last "]" + // ClosePrefix on before end char: ] ClosePrefix string } @@ -23,10 +23,14 @@ type ArrFormatter struct { func NewFormatter(arr any) *ArrFormatter { f := &ArrFormatter{} f.Src = arr - return f } +// FormatIndent array data to string. +func FormatIndent(arr any, indent string) string { + return NewFormatter(arr).WithIndent(indent).Format() +} + // WithFn for config self func (f *ArrFormatter) WithFn(fn func(f *ArrFormatter)) *ArrFormatter { fn(f) @@ -47,7 +51,6 @@ func (f *ArrFormatter) FormatTo(w io.Writer) { // Format to string func (f *ArrFormatter) String() string { - f.Format() return f.Format() } @@ -118,8 +121,3 @@ func (f *ArrFormatter) doFormat() { } writer.WriteByte(']') } - -// FormatIndent array data to string. -func FormatIndent(arr any, indent string) string { - return NewFormatter(arr).WithIndent(indent).Format() -} diff --git a/vendor/github.com/gookit/goutil/arrutil/list.go b/vendor/github.com/gookit/goutil/arrutil/list.go new file mode 100644 index 000000000..2c938c19d --- /dev/null +++ b/vendor/github.com/gookit/goutil/arrutil/list.go @@ -0,0 +1,216 @@ +package arrutil + +import ( + "sort" + "strings" + + "github.com/gookit/goutil/comdef" +) + +// Ints type +type Ints[T comdef.Integer] []T + +// String to string +func (is Ints[T]) String() string { + return ToString(is) +} + +// Has given element +func (is Ints[T]) Has(i T) bool { + for _, iv := range is { + if i == iv { + return true + } + } + return false +} + +// First element value. +func (is Ints[T]) First(defVal ...T) T { + if len(is) > 0 { + return is[0] + } + + if len(defVal) > 0 { + return defVal[0] + } + panic("empty integer slice") +} + +// Last element value. +func (is Ints[T]) Last(defVal ...T) T { + if len(is) > 0 { + return is[len(is)-1] + } + + if len(defVal) > 0 { + return defVal[0] + } + panic("empty integer slice") +} + +// Sort the int slice +func (is Ints[T]) Sort() { + sort.Sort(is) +} + +// Len get length +func (is Ints[T]) Len() int { + return len(is) +} + +// Less compare two elements +func (is Ints[T]) Less(i, j int) bool { + return is[i] < is[j] +} + +// Swap elements by indexes +func (is Ints[T]) Swap(i, j int) { + is[i], is[j] = is[j], is[i] +} + +// Strings type +type Strings []string + +// String to string +func (ss Strings) String() string { + return strings.Join(ss, ",") +} + +// Join to string +func (ss Strings) Join(sep string) string { + return strings.Join(ss, sep) +} + +// Has given element +func (ss Strings) Has(sub string) bool { + return ss.Contains(sub) +} + +// Contains given element +func (ss Strings) Contains(sub string) bool { + for _, s := range ss { + if s == sub { + return true + } + } + return false +} + +// First element value. +func (ss Strings) First(defVal ...string) string { + if len(ss) > 0 { + return ss[0] + } + + if len(defVal) > 0 { + return defVal[0] + } + panic("empty string list") +} + +// Last element value. +func (ss Strings) Last(defVal ...string) string { + if len(ss) > 0 { + return ss[len(ss)-1] + } + + if len(defVal) > 0 { + return defVal[0] + } + panic("empty string list") +} + +// Sort the string slice +func (ss Strings) Sort() { + sort.Strings(ss) +} + +// SortedList definition for compared type +type SortedList[T comdef.Compared] []T + +// Len get length +func (ls SortedList[T]) Len() int { + return len(ls) +} + +// Less compare two elements +func (ls SortedList[T]) Less(i, j int) bool { + return ls[i] < ls[j] +} + +// Swap elements by indexes +func (ls SortedList[T]) Swap(i, j int) { + ls[i], ls[j] = ls[j], ls[i] +} + +// IsEmpty check +func (ls SortedList[T]) IsEmpty() bool { + return len(ls) == 0 +} + +// String to string +func (ls SortedList[T]) String() string { + return ToString(ls) +} + +// Has given element +func (ls SortedList[T]) Has(el T) bool { + return ls.Contains(el) +} + +// Contains given element +func (ls SortedList[T]) Contains(el T) bool { + for _, v := range ls { + if v == el { + return true + } + } + return false +} + +// First element value. +func (ls SortedList[T]) First(defVal ...T) T { + if len(ls) > 0 { + return ls[0] + } + + if len(defVal) > 0 { + return defVal[0] + } + panic("empty list") +} + +// Last element value. +func (ls SortedList[T]) Last(defVal ...T) T { + if ln := len(ls); ln > 0 { + return ls[ln-1] + } + + if len(defVal) > 0 { + return defVal[0] + } + panic("empty list") +} + +// Remove given element +func (ls SortedList[T]) Remove(el T) SortedList[T] { + return Filter(ls, func(v T) bool { + return v != el + }) +} + +// Filter the slice, default will filter zero value. +func (ls SortedList[T]) Filter(filter ...comdef.MatchFunc[T]) SortedList[T] { + return Filter(ls, filter...) +} + +// Map the slice to new slice. TODO syntax ERROR: Method cannot have type parameters +// func (ls SortedList[T]) Map[V any](mapFn MapFn[T, V]) SortedList[V] { +// return Map(ls, mapFn) +// } + +// Sort the slice +func (ls SortedList[T]) Sort() { + sort.Sort(ls) +} diff --git a/vendor/github.com/gookit/goutil/arrutil/process.go b/vendor/github.com/gookit/goutil/arrutil/process.go new file mode 100644 index 000000000..05d960f6b --- /dev/null +++ b/vendor/github.com/gookit/goutil/arrutil/process.go @@ -0,0 +1,102 @@ +package arrutil + +import ( + "reflect" + + "github.com/gookit/goutil/comdef" +) + +// Reverse any T slice. +// +// eg: []string{"site", "user", "info", "0"} -> []string{"0", "info", "user", "site"} +func Reverse[T any](ls []T) { + ln := len(ls) + for i := 0; i < ln/2; i++ { + li := ln - i - 1 + ls[i], ls[li] = ls[li], ls[i] + } +} + +// Remove give element from slice []T. +// +// eg: []string{"site", "user", "info", "0"} -> []string{"site", "user", "info"} +func Remove[T comdef.Compared](ls []T, val T) []T { + return Filter(ls, func(el T) bool { + return el != val + }) +} + +// Filter given slice, default will filter zero value. +// +// Usage: +// +// // output: [a, b] +// ss := arrutil.Filter([]string{"a", "", "b", ""}) +func Filter[T any](ls []T, filter ...comdef.MatchFunc[T]) []T { + var fn comdef.MatchFunc[T] + if len(filter) > 0 && filter[0] != nil { + fn = filter[0] + } else { + fn = func(el T) bool { + return !reflect.ValueOf(el).IsZero() + } + } + + newLs := make([]T, 0, len(ls)) + for _, el := range ls { + if fn(el) { + newLs = append(newLs, el) + } + } + return newLs +} + +// MapFn map handle function type. +type MapFn[T any, V any] func(input T) (target V, find bool) + +// Map a list to new list +// +// eg: mapping [object0{},object1{},...] to flatten list [object0.someKey, object1.someKey, ...] +func Map[T any, V any](list []T, mapFn MapFn[T, V]) []V { + flatArr := make([]V, 0, len(list)) + + for _, obj := range list { + if target, ok := mapFn(obj); ok { + flatArr = append(flatArr, target) + } + } + return flatArr +} + +// Column alias of Map func +func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V { + return Map(list, mapFn) +} + +// Unique value in the given slice data. +func Unique[T ~string | comdef.XintOrFloat](list []T) []T { + if len(list) < 2 { + return list + } + + valMap := make(map[T]struct{}, len(list)) + uniArr := make([]T, 0, len(list)) + + for _, t := range list { + if _, ok := valMap[t]; !ok { + valMap[t] = struct{}{} + uniArr = append(uniArr, t) + } + } + return uniArr +} + +// IndexOf value in given slice. +func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int { + for i, v := range list { + if v == val { + return i + } + } + return -1 +} diff --git a/vendor/github.com/gookit/goutil/arrutil/strings.go b/vendor/github.com/gookit/goutil/arrutil/strings.go new file mode 100644 index 000000000..55968a41f --- /dev/null +++ b/vendor/github.com/gookit/goutil/arrutil/strings.go @@ -0,0 +1,137 @@ +package arrutil + +import ( + "strconv" + "strings" + + "github.com/gookit/goutil/comdef" +) + +// StringsToAnys convert []string to []any +func StringsToAnys(ss []string) []any { + args := make([]any, len(ss)) + for i, s := range ss { + args[i] = s + } + return args +} + +// StringsToSlice convert []string to []any. alias of StringsToAnys() +func StringsToSlice(ss []string) []any { + return StringsToAnys(ss) +} + +// StringsAsInts convert and ignore error +func StringsAsInts(ss []string) []int { + ints, _ := StringsTryInts(ss) + return ints +} + +// StringsToInts string slice to int slice +func StringsToInts(ss []string) (ints []int, err error) { + return StringsTryInts(ss) +} + +// StringsTryInts string slice to int slice +func StringsTryInts(ss []string) (ints []int, err error) { + for _, str := range ss { + iVal, err := strconv.Atoi(str) + if err != nil { + return nil, err + } + + ints = append(ints, iVal) + } + return +} + +// StringsUnique unique string slice +func StringsUnique(ss []string) []string { + var unique []string + for _, s := range ss { + if !StringsContains(unique, s) { + unique = append(unique, s) + } + } + return unique +} + +// StringsContains check string slice contains string +func StringsContains(ss []string, s string) bool { + for _, v := range ss { + if v == s { + return true + } + } + return false +} + +// StringsRemove value form a string slice +func StringsRemove(ss []string, s string) []string { + return StringsFilter(ss, func(el string) bool { + return s != el + }) +} + +// StringsFilter given strings, default will filter emtpy string. +// +// Usage: +// +// // output: [a, b] +// ss := arrutil.StringsFilter([]string{"a", "", "b", ""}) +func StringsFilter(ss []string, filter ...comdef.StringMatchFunc) []string { + var fn comdef.StringMatchFunc + if len(filter) > 0 && filter[0] != nil { + fn = filter[0] + } else { + fn = func(s string) bool { + return s != "" + } + } + + ns := make([]string, 0, len(ss)) + for _, s := range ss { + if fn(s) { + ns = append(ns, s) + } + } + return ns +} + +// StringsMap handle each string item, map to new strings +func StringsMap(ss []string, mapFn func(s string) string) []string { + ns := make([]string, 0, len(ss)) + for _, s := range ss { + ns = append(ns, mapFn(s)) + } + return ns +} + +// TrimStrings trim string slice item. +// +// Usage: +// +// // output: [a, b, c] +// ss := arrutil.TrimStrings([]string{",a", "b.", ",.c,"}, ",.") +func TrimStrings(ss []string, cutSet ...string) []string { + cutSetLn := len(cutSet) + hasCutSet := cutSetLn > 0 && cutSet[0] != "" + + var trimSet string + if hasCutSet { + trimSet = cutSet[0] + } + if cutSetLn > 1 { + trimSet = strings.Join(cutSet, "") + } + + ns := make([]string, 0, len(ss)) + for _, str := range ss { + if hasCutSet { + ns = append(ns, strings.Trim(str, trimSet)) + } else { + ns = append(ns, strings.TrimSpace(str)) + } + } + return ns +} diff --git a/vendor/github.com/gookit/goutil/basefn/basefunc.go b/vendor/github.com/gookit/goutil/basefn/basefn.go similarity index 68% rename from vendor/github.com/gookit/goutil/basefn/basefunc.go rename to vendor/github.com/gookit/goutil/basefn/basefn.go index decc3187d..8b2855e47 100644 --- a/vendor/github.com/gookit/goutil/basefn/basefunc.go +++ b/vendor/github.com/gookit/goutil/basefn/basefn.go @@ -1,13 +1,52 @@ // Package basefn provide some no-dependents util functions package basefn -import "fmt" +import ( + "errors" + "fmt" +) // Panicf format panic message use fmt.Sprintf func Panicf(format string, v ...any) { panic(fmt.Sprintf(format, v...)) } +// PanicIf if cond = true, panics with error message +func PanicIf(cond bool, fmtAndArgs ...any) { + if cond { + panic(errors.New(formatWithArgs(fmtAndArgs))) + } +} + +func formatWithArgs(fmtAndArgs []any) string { + ln := len(fmtAndArgs) + if ln == 0 { + return "" + } + + first := fmtAndArgs[0] + + if ln == 1 { + if msgAsStr, ok := first.(string); ok { + return msgAsStr + } + return fmt.Sprintf("%+v", first) + } + + // is template string. + if tplStr, ok := first.(string); ok { + return fmt.Sprintf(tplStr, fmtAndArgs[1:]...) + } + return fmt.Sprint(fmtAndArgs...) +} + +// PanicErr panics if error is not empty +func PanicErr(err error) { + if err != nil { + panic(err) + } +} + // MustOK if error is not empty, will panic func MustOK(err error) { if err != nil { diff --git a/vendor/github.com/gookit/goutil/byteutil/buffer.go b/vendor/github.com/gookit/goutil/byteutil/buffer.go index aa03183e3..0ae520c74 100644 --- a/vendor/github.com/gookit/goutil/byteutil/buffer.go +++ b/vendor/github.com/gookit/goutil/byteutil/buffer.go @@ -6,11 +6,13 @@ import ( ) // Buffer wrap and extends the bytes.Buffer, add some useful methods +// and implements the io.Writer, io.Closer and stdio.Flusher interfaces type Buffer struct { bytes.Buffer // custom error for testing CloseErr error FlushErr error + SyncErr error } // NewBuffer instance @@ -117,3 +119,8 @@ func (b *Buffer) Close() error { func (b *Buffer) Flush() error { return b.FlushErr } + +// Sync anf flush buffer +func (b *Buffer) Sync() error { + return b.SyncErr +} diff --git a/vendor/github.com/gookit/goutil/byteutil/byteutil.go b/vendor/github.com/gookit/goutil/byteutil/byteutil.go index 45c394556..6f3044d25 100644 --- a/vendor/github.com/gookit/goutil/byteutil/byteutil.go +++ b/vendor/github.com/gookit/goutil/byteutil/byteutil.go @@ -1,14 +1,40 @@ +// Package byteutil provides some useful functions for byte slice. package byteutil import ( "bytes" + "crypto/md5" + "encoding/hex" "fmt" "math/rand" "strconv" "time" - "unsafe" ) +// Md5 Generate a 32-bit md5 bytes +func Md5(src any) []byte { + h := md5.New() + + switch val := src.(type) { + case []byte: + h.Write(val) + case string: + h.Write([]byte(val)) + default: + h.Write([]byte(fmt.Sprint(src))) + } + + bs := h.Sum(nil) // cap(bs) == 16 + dst := make([]byte, hex.EncodedLen(len(bs))) + hex.Encode(dst, bs) + return dst +} + +// ShortMd5 Generate a 16-bit md5 bytes. remove first 8 and last 8 bytes from 32-bit md5. +func ShortMd5(src any) []byte { + return Md5(src)[8:24] +} + // Random bytes generate func Random(length int) ([]byte, error) { b := make([]byte, length) @@ -27,32 +53,6 @@ func FirstLine(bs []byte) []byte { return bs } -// StrOrErr convert to string, return empty string on error. -func StrOrErr(bs []byte, err error) (string, error) { - if err != nil { - return "", err - } - return string(bs), err -} - -// SafeString convert to string, return empty string on error. -func SafeString(bs []byte, err error) string { - if err != nil { - return "" - } - return string(bs) -} - -// String unsafe convert bytes to string -func String(b []byte) string { - return *(*string)(unsafe.Pointer(&b)) -} - -// ToString convert bytes to string -func ToString(b []byte) string { - return *(*string)(unsafe.Pointer(&b)) -} - // AppendAny append any value to byte slice func AppendAny(dst []byte, v any) []byte { if v == nil { @@ -104,12 +104,19 @@ func AppendAny(dst []byte, v any) []byte { return dst } -// Cut bytes. like the strings.Cut() +// Cut bytes by one byte char. like bytes.Cut(), but sep is byte. func Cut(bs []byte, sep byte) (before, after []byte, found bool) { - if i := bytes.IndexByte(bs, sep); i >= 0 { - return bs[:i], bs[i+1:], true - } + return bytes.Cut(bs, []byte{sep}) +} - before = bs +// SafeCut bytes by one byte char. always return before and after +func SafeCut(bs []byte, sep byte) (before, after []byte) { + before, after, _ = bytes.Cut(bs, []byte{sep}) + return +} + +// SafeCuts bytes by sub bytes. like the bytes.Cut(), but always return before and after +func SafeCuts(bs []byte, sep []byte) (before, after []byte) { + before, after, _ = bytes.Cut(bs, sep) return } diff --git a/vendor/github.com/gookit/goutil/byteutil/bytex.go b/vendor/github.com/gookit/goutil/byteutil/bytex.go deleted file mode 100644 index e66ea61f5..000000000 --- a/vendor/github.com/gookit/goutil/byteutil/bytex.go +++ /dev/null @@ -1,19 +0,0 @@ -// Package byteutil Provide some bytes utils functions or structs -package byteutil - -import ( - "crypto/md5" - "fmt" -) - -// Md5 Generate a 32-bit md5 bytes -func Md5(src any) []byte { - h := md5.New() - - if s, ok := src.(string); ok { - h.Write([]byte(s)) - } else { - h.Write([]byte(fmt.Sprint(src))) - } - return h.Sum(nil) -} diff --git a/vendor/github.com/gookit/goutil/byteutil/conv.go b/vendor/github.com/gookit/goutil/byteutil/conv.go new file mode 100644 index 000000000..b080bb173 --- /dev/null +++ b/vendor/github.com/gookit/goutil/byteutil/conv.go @@ -0,0 +1,109 @@ +package byteutil + +import ( + "fmt" + "strconv" + "time" + "unsafe" + + "github.com/gookit/goutil/comdef" +) + +// StrOrErr convert to string, return empty string on error. +func StrOrErr(bs []byte, err error) (string, error) { + if err != nil { + return "", err + } + return string(bs), err +} + +// SafeString convert to string, return empty string on error. +func SafeString(bs []byte, err error) string { + if err != nil { + return "" + } + return string(bs) +} + +// String unsafe convert bytes to string +func String(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// ToString convert bytes to string +func ToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// ToBytes convert any value to []byte. return error on convert failed. +func ToBytes(v any) ([]byte, error) { + return ToBytesWithFunc(v, nil) +} + +// SafeBytes convert any value to []byte. use fmt.Sprint() on convert failed. +func SafeBytes(v any) []byte { + bs, _ := ToBytesWithFunc(v, func(v any) ([]byte, error) { + return []byte(fmt.Sprint(v)), nil + }) + return bs +} + +// ToBytesFunc convert any value to []byte +type ToBytesFunc = func(v any) ([]byte, error) + +// ToBytesWithFunc convert any value to []byte with custom fallback func. +// +// refer the strutil.ToStringWithFunc +// +// On not convert: +// - If usrFn is nil, will return comdef.ErrConvType. +// - If usrFn is not nil, will call it to convert. +func ToBytesWithFunc(v any, usrFn ToBytesFunc) ([]byte, error) { + if v == nil { + return nil, nil + } + + switch val := v.(type) { + case []byte: + return val, nil + case string: + return []byte(val), nil + case int: + return []byte(strconv.Itoa(val)), nil + case int8: + return []byte(strconv.Itoa(int(val))), nil + case int16: + return []byte(strconv.Itoa(int(val))), nil + case int32: // same as `rune` + return []byte(strconv.Itoa(int(val))), nil + case int64: + return []byte(strconv.FormatInt(val, 10)), nil + case uint: + return []byte(strconv.FormatUint(uint64(val), 10)), nil + case uint8: + return []byte(strconv.FormatUint(uint64(val), 10)), nil + case uint16: + return []byte(strconv.FormatUint(uint64(val), 10)), nil + case uint32: + return []byte(strconv.FormatUint(uint64(val), 10)), nil + case uint64: + return []byte(strconv.FormatUint(val, 10)), nil + case float32: + return []byte(strconv.FormatFloat(float64(val), 'f', -1, 32)), nil + case float64: + return []byte(strconv.FormatFloat(val, 'f', -1, 64)), nil + case bool: + return []byte(strconv.FormatBool(val)), nil + case time.Duration: + return []byte(strconv.FormatInt(int64(val), 10)), nil + case fmt.Stringer: + return []byte(val.String()), nil + case error: + return []byte(val.Error()), nil + default: + if usrFn == nil { + return nil, comdef.ErrConvType + } + return usrFn(val) + } +} diff --git a/vendor/github.com/gookit/goutil/byteutil/encoder.go b/vendor/github.com/gookit/goutil/byteutil/encoder.go index 8ec965e5d..15717c59e 100644 --- a/vendor/github.com/gookit/goutil/byteutil/encoder.go +++ b/vendor/github.com/gookit/goutil/byteutil/encoder.go @@ -5,6 +5,12 @@ import ( "encoding/hex" ) +// BytesEncodeFunc type +type BytesEncodeFunc func(src []byte) []byte + +// BytesDecodeFunc type +type BytesDecodeFunc func(src []byte) ([]byte, error) + // BytesEncoder interface type BytesEncoder interface { Encode(src []byte) []byte @@ -13,12 +19,12 @@ type BytesEncoder interface { // StdEncoder implement the BytesEncoder type StdEncoder struct { - encodeFn func(src []byte) []byte - decodeFn func(src []byte) ([]byte, error) + encodeFn BytesEncodeFunc + decodeFn BytesDecodeFunc } // NewStdEncoder instance -func NewStdEncoder(encFn func(src []byte) []byte, decFn func(src []byte) ([]byte, error)) *StdEncoder { +func NewStdEncoder(encFn BytesEncodeFunc, decFn BytesDecodeFunc) *StdEncoder { return &StdEncoder{ encodeFn: encFn, decodeFn: decFn, diff --git a/vendor/github.com/gookit/goutil/byteutil/pool.go b/vendor/github.com/gookit/goutil/byteutil/pool.go index c6f09e018..8e8b6d80a 100644 --- a/vendor/github.com/gookit/goutil/byteutil/pool.go +++ b/vendor/github.com/gookit/goutil/byteutil/pool.go @@ -13,14 +13,14 @@ package byteutil // from https://github.com/minio/minio/blob/master/internal/bpool/bpool.go type ChanPool struct { c chan []byte - w int - wcap int + w int // init byte width + wcap int // set byte cap } // NewChanPool instance -func NewChanPool(maxSize int, width int, capWidth int) *ChanPool { +func NewChanPool(chSize int, width int, capWidth int) *ChanPool { return &ChanPool{ - c: make(chan []byte, maxSize), + c: make(chan []byte, chSize), w: width, wcap: capWidth, } @@ -30,8 +30,7 @@ func NewChanPool(maxSize int, width int, capWidth int) *ChanPool { // available in the pool. func (bp *ChanPool) Get() (b []byte) { select { - case b = <-bp.c: - // reuse existing buffer + case b = <-bp.c: // reuse existing buffer default: // create new buffer if bp.wcap > 0 { diff --git a/vendor/github.com/gookit/goutil/check.go b/vendor/github.com/gookit/goutil/check.go index a0b0a0fc3..5c73f5498 100644 --- a/vendor/github.com/gookit/goutil/check.go +++ b/vendor/github.com/gookit/goutil/check.go @@ -3,8 +3,8 @@ package goutil import ( "reflect" + "github.com/gookit/goutil/internal/checkfn" "github.com/gookit/goutil/reflects" - "github.com/gookit/goutil/stdutil" ) // IsNil value check @@ -15,6 +15,9 @@ func IsNil(v any) bool { return reflects.IsNil(reflect.ValueOf(v)) } +// IsZero value check, alias of the IsEmpty() +var IsZero = IsEmpty + // IsEmpty value check func IsEmpty(v any) bool { if v == nil { @@ -55,7 +58,7 @@ func IsEqual(src, dst any) bool { // string - check sub-string exists // array,slice - check sub-element exists func Contains(data, elem any) bool { - _, found := stdutil.CheckContains(data, elem) + _, found := checkfn.Contains(data, elem) return found } @@ -67,6 +70,6 @@ func Contains(data, elem any) bool { // string - check sub-string exists // array,slice - check sub-element exists func IsContains(data, elem any) bool { - _, found := stdutil.CheckContains(data, elem) + _, found := checkfn.Contains(data, elem) return found } diff --git a/vendor/github.com/gookit/goutil/cliutil/cmdline/builder.go b/vendor/github.com/gookit/goutil/cliutil/cmdline/builder.go index 1dceeec77..fac12bc9a 100644 --- a/vendor/github.com/gookit/goutil/cliutil/cmdline/builder.go +++ b/vendor/github.com/gookit/goutil/cliutil/cmdline/builder.go @@ -55,13 +55,13 @@ func (b *LineBuilder) WriteString(a string) (int, error) { if pos := strings.IndexByte(a, '"'); pos > -1 { quote = '\'' // fix: a = `--pretty=format:"one two three"` - if pos > 0 && '"' == a[len(a)-1] { + if pos > 0 && a[len(a)-1] == '"' { quote = 0 } } else if pos := strings.IndexByte(a, '\''); pos > -1 { quote = '"' // fix: a = "--pretty=format:'one two three'" - if pos > 0 && '\'' == a[len(a)-1] { + if pos > 0 && a[len(a)-1] == '\'' { quote = 0 } } else if a == "" || strings.ContainsRune(a, ' ') { diff --git a/vendor/github.com/gookit/goutil/cliutil/cmdline/parser.go b/vendor/github.com/gookit/goutil/cliutil/cmdline/parser.go index e59f0928c..eed290247 100644 --- a/vendor/github.com/gookit/goutil/cliutil/cmdline/parser.go +++ b/vendor/github.com/gookit/goutil/cliutil/cmdline/parser.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/gookit/goutil/comdef" - "github.com/gookit/goutil/internal/comfunc" + "github.com/gookit/goutil/internal/varexpr" "github.com/gookit/goutil/strutil" ) @@ -86,7 +86,7 @@ func (p *LineParser) Parse() []string { // enable parse Env var if p.ParseEnv { - p.Line = comfunc.ParseEnvVar(p.Line, nil) + p.Line = varexpr.SafeParse(p.Line) } p.nodes = strings.Split(p.Line, " ") diff --git a/vendor/github.com/gookit/goutil/comdef/comdef.go b/vendor/github.com/gookit/goutil/comdef/comdef.go index 06e86a2a4..54a16687a 100644 --- a/vendor/github.com/gookit/goutil/comdef/comdef.go +++ b/vendor/github.com/gookit/goutil/comdef/comdef.go @@ -1,38 +1,6 @@ // Package comdef provide some common type or constant definitions package comdef -import ( - "fmt" - "io" -) - -// ByteStringWriter interface -type ByteStringWriter interface { - io.Writer - io.ByteWriter - io.StringWriter - fmt.Stringer -} - -// StringWriteStringer interface -type StringWriteStringer interface { - io.StringWriter - fmt.Stringer -} - -// StringMatcher interface -type StringMatcher interface { - Match(s string) bool -} - -// StringMatchFunc definition -type StringMatchFunc func(s string) bool - -// Match satisfies the StringMatcher interface -func (fn StringMatchFunc) Match(s string) bool { - return fn(s) -} - type ( // MarshalFunc define MarshalFunc func(v any) ([]byte, error) @@ -40,3 +8,15 @@ type ( // UnmarshalFunc define UnmarshalFunc func(bts []byte, ptr any) error ) + +// IntCheckFunc check func +type IntCheckFunc func(val int) error + +// StrCheckFunc check func +type StrCheckFunc func(val string) error + +// ToStringFunc try to convert value to string, return error on fail +type ToStringFunc func(v any) (string, error) + +// SafeStringFunc safe convert value to string +type SafeStringFunc func(v any) string diff --git a/vendor/github.com/gookit/goutil/comdef/interface.go b/vendor/github.com/gookit/goutil/comdef/interface.go new file mode 100644 index 000000000..7718f4263 --- /dev/null +++ b/vendor/github.com/gookit/goutil/comdef/interface.go @@ -0,0 +1,70 @@ +package comdef + +import ( + "fmt" + "io" +) + +// ByteStringWriter interface +type ByteStringWriter interface { + io.Writer + io.ByteWriter + io.StringWriter + fmt.Stringer +} + +// StringWriteStringer interface +type StringWriteStringer interface { + io.StringWriter + fmt.Stringer +} + +// Int64able interface +type Int64able interface { + Int64() (int64, error) +} + +// +// +// Matcher type +// +// + +// Matcher interface +type Matcher[T any] interface { + Match(s T) bool +} + +// MatchFunc definition. implements Matcher interface +type MatchFunc[T any] func(v T) bool + +// Match satisfies the Matcher interface +func (fn MatchFunc[T]) Match(v T) bool { + return fn(v) +} + +// StringMatcher interface +type StringMatcher interface { + Match(s string) bool +} + +// StringMatchFunc definition +type StringMatchFunc func(s string) bool + +// Match satisfies the StringMatcher interface +func (fn StringMatchFunc) Match(s string) bool { + return fn(s) +} + +// StringHandler interface +type StringHandler interface { + Handle(s string) string +} + +// StringHandleFunc definition +type StringHandleFunc func(s string) string + +// Handle satisfies the StringHandler interface +func (fn StringHandleFunc) Handle(s string) string { + return fn(s) +} diff --git a/vendor/github.com/gookit/goutil/comdef/types.go b/vendor/github.com/gookit/goutil/comdef/types.go index 2fe167f2d..d180f0315 100644 --- a/vendor/github.com/gookit/goutil/comdef/types.go +++ b/vendor/github.com/gookit/goutil/comdef/types.go @@ -10,11 +10,16 @@ type Uint interface { ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr } -// Xint interface type. all int or uint types +// Xint interface type. alias of Integer type Xint interface { Int | Uint } +// Integer interface type. all int or uint types +type Integer interface { + Int | Uint +} + // Float interface type type Float interface { ~float32 | ~float64 @@ -30,16 +35,34 @@ type XintOrFloat interface { Int | Uint | Float } -// SortedType interface type. -// that supports the operators < <= >= >. +// SortedType interface type. same of constraints.Ordered +// +// it can be ordered, that supports the operators < <= >= >. // // contains: (x)int, float, ~string types type SortedType interface { Int | Uint | Float | ~string } +// Compared type. alias of constraints.SortedType +// +// TODO: use type alias, will error on go1.18 Error: types.go:50: interface contains type constraints +// type Compared = SortedType +type Compared interface { + Int | Uint | Float | ~string +} + +// SimpleType interface type. alias of ScalarType +// +// contains: (x)int, float, ~string, ~bool types +type SimpleType interface { + Int | Uint | Float | ~string | ~bool +} + // ScalarType interface type. // +// TIP: has bool type, it cannot be ordered +// // contains: (x)int, float, ~string, ~bool types type ScalarType interface { Int | Uint | Float | ~string | ~bool diff --git a/vendor/github.com/gookit/goutil/conv.go b/vendor/github.com/gookit/goutil/conv.go index 7686747da..6e97c1a48 100644 --- a/vendor/github.com/gookit/goutil/conv.go +++ b/vendor/github.com/gookit/goutil/conv.go @@ -1,9 +1,12 @@ package goutil import ( + "fmt" + "math" "reflect" "strconv" + "github.com/gookit/goutil/comdef" "github.com/gookit/goutil/internal/comfunc" "github.com/gookit/goutil/mathutil" "github.com/gookit/goutil/reflects" @@ -65,18 +68,167 @@ func ToUint(v any) (uint64, error) { return mathutil.ToUint(v) } +// BoolString convert bool to string +func BoolString(bl bool) string { + return strconv.FormatBool(bl) +} + // BaseTypeVal convert custom type or intX,uintX,floatX to generic base type. // -// intX/unitX => int64 +// intX => int64 +// unitX => uint64 // floatX => float64 // string => string // -// returns int64,string,float or error +// returns int64,uint64,string,float or error func BaseTypeVal(val any) (value any, err error) { return reflects.BaseTypeVal(reflect.ValueOf(val)) } -// BoolString convert -func BoolString(bl bool) string { - return strconv.FormatBool(bl) +// SafeKind convert input any value to given reflect.Kind type. +func SafeKind(val any, kind reflect.Kind) (newVal any) { + newVal, _ = ToKind(val, kind, nil) + return +} + +// SafeConv convert input any value to given reflect.Kind type. +func SafeConv(val any, kind reflect.Kind) (newVal any) { + newVal, _ = ToKind(val, kind, nil) + return +} + +// ConvTo convert input any value to given reflect.Kind. +func ConvTo(val any, kind reflect.Kind) (newVal any, err error) { + return ToKind(val, kind, nil) +} + +// ConvOrDefault convert input any value to given reflect.Kind. +// if fail will return default value. +func ConvOrDefault(val any, kind reflect.Kind, defVal any) any { + newVal, err := ToKind(val, kind, nil) + if err != nil { + return defVal + } + return newVal +} + +// ToType +// func ToType[T any](val any, kind reflect.Kind, fbFunc func(val any) (T, error)) (newVal T, err error) { +// switch typVal.(type) { // assert ERROR +// case string: +// } +// } + +// ToKind convert input any value to given reflect.Kind type. +// +// TIPs: Only support kind: string, bool, intX, uintX, floatX +// +// Examples: +// +// val, err := ToKind("123", reflect.Int) // 123 +func ToKind(val any, kind reflect.Kind, fbFunc func(val any) (any, error)) (newVal any, err error) { + switch kind { + case reflect.Int: + var dstV int + if dstV, err = mathutil.ToInt(val); err == nil { + if dstV > math.MaxInt { + return nil, fmt.Errorf("value overflow int. val: %v", val) + } + newVal = dstV + } + case reflect.Int8: + var dstV int + if dstV, err = mathutil.ToInt(val); err == nil { + if dstV > math.MaxInt8 { + return nil, fmt.Errorf("value overflow int8. val: %v", val) + } + newVal = int8(dstV) + } + case reflect.Int16: + var dstV int + if dstV, err = mathutil.ToInt(val); err == nil { + if dstV > math.MaxInt16 { + return nil, fmt.Errorf("value overflow int16. val: %v", val) + } + newVal = int16(dstV) + } + case reflect.Int32: + var dstV int + if dstV, err = mathutil.ToInt(val); err == nil { + if dstV > math.MaxInt32 { + return nil, fmt.Errorf("value overflow int32. val: %v", val) + } + newVal = int32(dstV) + } + case reflect.Int64: + var dstV int64 + if dstV, err = mathutil.ToInt64(val); err == nil { + newVal = dstV + } + case reflect.Uint: + var dstV uint64 + if dstV, err = mathutil.ToUint(val); err == nil { + newVal = uint(dstV) + } + case reflect.Uint8: + var dstV uint64 + if dstV, err = mathutil.ToUint(val); err == nil { + if dstV > math.MaxUint8 { + return nil, fmt.Errorf("value overflow uint8. val: %v", val) + } + newVal = uint8(dstV) + } + case reflect.Uint16: + var dstV uint64 + if dstV, err = mathutil.ToUint(val); err == nil { + if dstV > math.MaxUint16 { + return nil, fmt.Errorf("value overflow uint16. val: %v", val) + } + newVal = uint16(dstV) + } + case reflect.Uint32: + var dstV uint64 + if dstV, err = mathutil.ToUint(val); err == nil { + if dstV > math.MaxUint32 { + return nil, fmt.Errorf("value overflow uint32. val: %v", val) + } + newVal = uint32(dstV) + } + case reflect.Uint64: + var dstV uint64 + if dstV, err = mathutil.ToUint(val); err == nil { + newVal = dstV + } + case reflect.Float32: + var dstV float64 + if dstV, err = mathutil.ToFloat(val); err == nil { + if dstV > math.MaxFloat32 { + return nil, fmt.Errorf("value overflow float32. val: %v", val) + } + newVal = float32(dstV) + } + case reflect.Float64: + var dstV float64 + if dstV, err = mathutil.ToFloat(val); err == nil { + newVal = dstV + } + case reflect.String: + var dstV string + if dstV, err = strutil.ToString(val); err == nil { + newVal = dstV + } + case reflect.Bool: + if bl, err1 := comfunc.ToBool(val); err1 == nil { + newVal = bl + } else { + err = err1 + } + default: + if fbFunc != nil { + newVal, err = fbFunc(val) + } else { + err = comdef.ErrConvType + } + } + return } diff --git a/vendor/github.com/gookit/goutil/encodes/encodes.go b/vendor/github.com/gookit/goutil/encodes/encodes.go new file mode 100644 index 000000000..306325ea2 --- /dev/null +++ b/vendor/github.com/gookit/goutil/encodes/encodes.go @@ -0,0 +1,66 @@ +package encodes + +import ( + "encoding/base32" + "encoding/base64" +) + +// BaseEncoder interface +type BaseEncoder interface { + Encode(dst []byte, src []byte) + EncodeToString(src []byte) string + Decode(dst []byte, src []byte) (n int, err error) + DecodeString(s string) ([]byte, error) +} + +// +// -------------------- base encode -------------------- +// + +// base32 encoding with no padding +var ( + B32Std = base32.StdEncoding.WithPadding(base32.NoPadding) + B32Hex = base32.HexEncoding.WithPadding(base32.NoPadding) +) + +// B32Encode base32 encode +func B32Encode(str string) string { + return B32Std.EncodeToString([]byte(str)) +} + +// B32Decode base32 decode +func B32Decode(str string) string { + dec, _ := B32Std.DecodeString(str) + return string(dec) +} + +// base64 encoding with no padding +var ( + B64Std = base64.StdEncoding.WithPadding(base64.NoPadding) + B64URL = base64.URLEncoding.WithPadding(base64.NoPadding) +) + +// B64Encode base64 encode +func B64Encode(str string) string { + return B64Std.EncodeToString([]byte(str)) +} + +// B64EncodeBytes base64 encode +func B64EncodeBytes(src []byte) []byte { + buf := make([]byte, B64Std.EncodedLen(len(src))) + B64Std.Encode(buf, src) + return buf +} + +// B64Decode base64 decode +func B64Decode(str string) string { + dec, _ := B64Std.DecodeString(str) + return string(dec) +} + +// B64DecodeBytes base64 decode +func B64DecodeBytes(str []byte) []byte { + dbuf := make([]byte, B64Std.DecodedLen(len(str))) + n, _ := B64Std.Decode(dbuf, str) + return dbuf[:n] +} diff --git a/vendor/github.com/gookit/goutil/envutil/README.md b/vendor/github.com/gookit/goutil/envutil/README.md index 85d18c90b..48901adf1 100644 --- a/vendor/github.com/gookit/goutil/envutil/README.md +++ b/vendor/github.com/gookit/goutil/envutil/README.md @@ -1,6 +1,6 @@ # Env Util -Provide some commonly ENV util functions. +Provide some commonly system or go ENV util functions. ## Install diff --git a/vendor/github.com/gookit/goutil/envutil/envutil.go b/vendor/github.com/gookit/goutil/envutil/envutil.go index f9a312da2..9a446fde1 100644 --- a/vendor/github.com/gookit/goutil/envutil/envutil.go +++ b/vendor/github.com/gookit/goutil/envutil/envutil.go @@ -4,7 +4,7 @@ package envutil import ( "os" - "github.com/gookit/goutil/internal/comfunc" + "github.com/gookit/goutil/internal/varexpr" ) // ValueGetter Env value provider func. @@ -17,14 +17,13 @@ var ValueGetter = os.Getenv // is alias of the os.ExpandEnv() func VarReplace(s string) string { return os.ExpandEnv(s) } -// VarParse alias of the ParseValue -func VarParse(val string) string { - return comfunc.ParseEnvVar(val, ValueGetter) -} - -// ParseEnvValue alias of the ParseValue -func ParseEnvValue(val string) string { - return comfunc.ParseEnvVar(val, ValueGetter) +// ParseOrErr parse ENV var value from input string, support default value. +// +// Diff with the ParseValue, this support return error. +// +// With error format: ${VAR_NAME | ?error} +func ParseOrErr(val string) (string, error) { + return varexpr.Parse(val) } // ParseValue parse ENV var value from input string, support default value. @@ -38,8 +37,18 @@ func ParseEnvValue(val string) string { // // envutil.ParseValue("${ APP_NAME }") // envutil.ParseValue("${ APP_ENV | dev }") -func ParseValue(val string) (newVal string) { - return comfunc.ParseEnvVar(val, ValueGetter) +func ParseValue(val string) string { + return varexpr.SafeParse(val) +} + +// VarParse alias of the ParseValue +func VarParse(val string) string { + return varexpr.SafeParse(val) +} + +// ParseEnvValue alias of the ParseValue +func ParseEnvValue(val string) string { + return varexpr.SafeParse(val) } // SetEnvMap set multi ENV(string-map) to os diff --git a/vendor/github.com/gookit/goutil/envutil/get.go b/vendor/github.com/gookit/goutil/envutil/get.go index 6250c5b38..4cd9d76ea 100644 --- a/vendor/github.com/gookit/goutil/envutil/get.go +++ b/vendor/github.com/gookit/goutil/envutil/get.go @@ -4,6 +4,7 @@ import ( "os" "path/filepath" + "github.com/gookit/goutil/basefn" "github.com/gookit/goutil/internal/comfunc" "github.com/gookit/goutil/strutil" ) @@ -22,11 +23,7 @@ func GetInt(name string, def ...int) int { if val := os.Getenv(name); val != "" { return strutil.QuietInt(val) } - - if len(def) > 0 { - return def[0] - } - return 0 + return basefn.FirstOr(def, 0) } // GetBool get bool ENV value by key name, can with default value @@ -34,11 +31,7 @@ func GetBool(name string, def ...bool) bool { if val := os.Getenv(name); val != "" { return strutil.QuietBool(val) } - - if len(def) > 0 { - return def[0] - } - return false + return basefn.FirstOr(def, false) } // GetMulti ENV values by input names. diff --git a/vendor/github.com/gookit/goutil/errorx/assert.go b/vendor/github.com/gookit/goutil/errorx/assert.go index 696b45885..961290b51 100644 --- a/vendor/github.com/gookit/goutil/errorx/assert.go +++ b/vendor/github.com/gookit/goutil/errorx/assert.go @@ -30,7 +30,7 @@ func IsIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error { if arrutil.NotIn(value, list) { var errMsg string if len(fmtAndArgs) > 0 { - errMsg = comfunc.FormatTplAndArgs(fmtAndArgs) + errMsg = comfunc.FormatWithArgs(fmtAndArgs) } else { errMsg = fmt.Sprintf("value should be in the %v", list) } @@ -44,7 +44,7 @@ func NotIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error { if arrutil.In(value, list) { var errMsg string if len(fmtAndArgs) > 0 { - errMsg = comfunc.FormatTplAndArgs(fmtAndArgs) + errMsg = comfunc.FormatWithArgs(fmtAndArgs) } else { errMsg = fmt.Sprintf("value should not be in the %v", list) } @@ -53,9 +53,9 @@ func NotIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error { return nil } -func formatErrMsg(errMsg string, fmtAndArgs []any) string { +func formatErrMsg(defMsg string, fmtAndArgs []any) string { if len(fmtAndArgs) > 0 { - errMsg = comfunc.FormatTplAndArgs(fmtAndArgs) + return comfunc.FormatWithArgs(fmtAndArgs) } - return errMsg + return defMsg } diff --git a/vendor/github.com/gookit/goutil/errorx/errors.go b/vendor/github.com/gookit/goutil/errorx/errors.go index 0dffef5d4..7e0ed8d2e 100644 --- a/vendor/github.com/gookit/goutil/errorx/errors.go +++ b/vendor/github.com/gookit/goutil/errorx/errors.go @@ -77,11 +77,14 @@ func (e *errorR) GoString() string { return e.String() } -// ErrMap multi error map -type ErrMap map[string]error +// ErrorM multi error map +type ErrorM map[string]error + +// ErrMap alias of ErrorM +type ErrMap = ErrorM // Error string -func (e ErrMap) Error() string { +func (e ErrorM) Error() string { var sb strings.Builder for name, err := range e { sb.WriteString(name) @@ -93,7 +96,7 @@ func (e ErrMap) Error() string { } // ErrorOrNil error -func (e ErrMap) ErrorOrNil() error { +func (e ErrorM) ErrorOrNil() error { if len(e) == 0 { return nil } @@ -101,12 +104,12 @@ func (e ErrMap) ErrorOrNil() error { } // IsEmpty error -func (e ErrMap) IsEmpty() bool { +func (e ErrorM) IsEmpty() bool { return len(e) == 0 } // One error -func (e ErrMap) One() error { +func (e ErrorM) One() error { for _, err := range e { return err } diff --git a/vendor/github.com/gookit/goutil/errorx/errorx.go b/vendor/github.com/gookit/goutil/errorx/errorx.go index b7b2625fa..3595e529c 100644 --- a/vendor/github.com/gookit/goutil/errorx/errorx.go +++ b/vendor/github.com/gookit/goutil/errorx/errorx.go @@ -71,7 +71,7 @@ func (e *ErrorX) Unwrap() error { return e.prev } -// Format error +// Format error, will output stack information. func (e *ErrorX) Format(s fmt.State, verb rune) { // format current error: only output on have msg if len(e.msg) > 0 { @@ -103,7 +103,7 @@ func (e *ErrorX) GoString() string { return buf.String() } -// Error to string, not contains stack information. +// Error msg string, not contains stack information. func (e *ErrorX) Error() string { var buf bytes.Buffer e.writeMsgTo(&buf) @@ -265,6 +265,7 @@ func WithStack(err error) error { if err == nil { return nil } + return &ErrorX{ msg: err.Error(), // prev: err, @@ -277,6 +278,7 @@ func Traced(err error) error { if err == nil { return nil } + return &ErrorX{ msg: err.Error(), stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth), @@ -288,6 +290,7 @@ func Stacked(err error) error { if err == nil { return nil } + return &ErrorX{ msg: err.Error(), stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth), diff --git a/vendor/github.com/gookit/goutil/errorx/stack.go b/vendor/github.com/gookit/goutil/errorx/stack.go index 13f78e587..5ecfa2af7 100644 --- a/vendor/github.com/gookit/goutil/errorx/stack.go +++ b/vendor/github.com/gookit/goutil/errorx/stack.go @@ -99,7 +99,7 @@ func FuncForPC(pc uintptr) *Func { } } -// FileLine of the func +// FileLine returns the file name and line number of the source code func (f *Func) FileLine() (file string, line int) { return f.Func.FileLine(f.pc) } @@ -108,7 +108,7 @@ func (f *Func) FileLine() (file string, line int) { // // Returns eg: // -// github.com/gookit/goutil/errorx_test.TestWithPrev(), errorx_test.go:34 +// "github.com/gookit/goutil/errorx_test.TestWithPrev(), errorx_test.go:34" func (f *Func) Location() string { file, line := f.FileLine() diff --git a/vendor/github.com/gookit/goutil/errorx/util.go b/vendor/github.com/gookit/goutil/errorx/util.go index 8558785a2..83acf8c75 100644 --- a/vendor/github.com/gookit/goutil/errorx/util.go +++ b/vendor/github.com/gookit/goutil/errorx/util.go @@ -68,12 +68,27 @@ func Unwrap(err error) error { // Previous alias of Unwrap() func Previous(err error) error { return Unwrap(err) } +// IsErrorX check +func IsErrorX(err error) (ok bool) { + _, ok = err.(*ErrorX) + return +} + // ToErrorX convert check func ToErrorX(err error) (ex *ErrorX, ok bool) { ex, ok = err.(*ErrorX) return } +// MustEX convert error to *ErrorX, panic if err check failed. +func MustEX(err error) *ErrorX { + ex, ok := err.(*ErrorX) + if !ok { + panic("errorx: error is not *ErrorX") + } + return ex +} + // Has contains target error, or err is eq target. // alias of errors.Is() func Has(err, target error) bool { diff --git a/vendor/github.com/gookit/goutil/fsutil/check.go b/vendor/github.com/gookit/goutil/fsutil/check.go index 918ea7819..a015d40b0 100644 --- a/vendor/github.com/gookit/goutil/fsutil/check.go +++ b/vendor/github.com/gookit/goutil/fsutil/check.go @@ -2,6 +2,7 @@ package fsutil import ( "bytes" + "io" "os" "path" "path/filepath" @@ -82,6 +83,18 @@ func IsAbsPath(aPath string) bool { return false } +// IsEmptyDir reports whether the named directory is empty. +func IsEmptyDir(dirPath string) bool { + f, err := os.Open(dirPath) + if err != nil { + return false + } + defer f.Close() + + _, err = f.Readdirnames(1) + return err == io.EOF +} + // ImageMimeTypes refer net/http package var ImageMimeTypes = map[string]string{ "bmp": "image/bmp", diff --git a/vendor/github.com/gookit/goutil/fsutil/define.go b/vendor/github.com/gookit/goutil/fsutil/define.go new file mode 100644 index 000000000..09bb232c9 --- /dev/null +++ b/vendor/github.com/gookit/goutil/fsutil/define.go @@ -0,0 +1,109 @@ +package fsutil + +import ( + "io/fs" + + "github.com/gookit/goutil/comdef" + "github.com/gookit/goutil/strutil" +) + +const ( + // MimeSniffLen sniff Length, use for detect file mime type + MimeSniffLen = 512 +) + +// NameMatchFunc name match func, alias of comdef.StringMatchFunc +type NameMatchFunc = comdef.StringMatchFunc + +// PathMatchFunc path match func. alias of comdef.StringMatchFunc +type PathMatchFunc = comdef.StringMatchFunc + +// Entry extends fs.DirEntry, add some useful methods +type Entry interface { + fs.DirEntry + // Path get file/dir full path. eg: "/path/to/file.go" + Path() string + // Info get file info. like fs.DirEntry.Info(), but will cache result. + Info() (fs.FileInfo, error) +} + +type entry struct { + fs.DirEntry + path string + stat fs.FileInfo + sErr error +} + +// NewEntry create a new Entry instance +func NewEntry(fPath string, ent fs.DirEntry) Entry { + return &entry{ + path: fPath, + DirEntry: ent, + } +} + +// Path get full file/dir path. eg: "/path/to/file.go" +func (e *entry) Path() string { + return e.path +} + +// Info get file info, will cache result +func (e *entry) Info() (fs.FileInfo, error) { + if e.stat == nil { + e.stat, e.sErr = e.DirEntry.Info() + } + return e.stat, e.sErr +} + +// String get string representation +func (e *entry) String() string { + return strutil.OrCond(e.IsDir(), "dir: ", "file: ") + e.Path() +} + +// FileInfo extends fs.FileInfo, add some useful methods +type FileInfo interface { + fs.FileInfo + // Path get file full path. eg: "/path/to/file.go" + Path() string +} + +type fileInfo struct { + fs.FileInfo + fullPath string +} + +// NewFileInfo create a new FileInfo instance +func NewFileInfo(fPath string, info fs.FileInfo) FileInfo { + return &fileInfo{ + fullPath: fPath, + FileInfo: info, + } +} + +// Path get file full path. eg: "/path/to/file.go" +func (fi *fileInfo) Path() string { + return fi.fullPath +} + +// FileInfos type for FileInfo slice +// +// implements sort.Interface: +// +// sorts by oldest time modified in the file info. +// eg: [old_220211, old_220212, old_220213] +type FileInfos []FileInfo + +// Len get length +func (fis FileInfos) Len() int { + return len(fis) +} + +// Swap swap values +func (fis FileInfos) Swap(i, j int) { + fis[i], fis[j] = fis[j], fis[i] +} + +// Less check by mod time +func (fis FileInfos) Less(i, j int) bool { + return fis[j].ModTime().After(fis[i].ModTime()) +} diff --git a/vendor/github.com/gookit/goutil/fsutil/find.go b/vendor/github.com/gookit/goutil/fsutil/find.go index 80082481e..19ab7f585 100644 --- a/vendor/github.com/gookit/goutil/fsutil/find.go +++ b/vendor/github.com/gookit/goutil/fsutil/find.go @@ -7,10 +7,66 @@ import ( "path/filepath" "github.com/gookit/goutil/arrutil" - "github.com/gookit/goutil/comdef" + "github.com/gookit/goutil/internal/comfunc" "github.com/gookit/goutil/strutil" ) +// FilePathInDirs get full file path in dirs. +// +// Params: +// - file: can be relative path, file name, full path. +// - dirs: dir paths +func FilePathInDirs(file string, dirs ...string) string { + file = comfunc.ExpandHome(file) + if FileExists(file) { + return file + } + + for _, dirPath := range dirs { + fPath := JoinSubPaths(dirPath, file) + if FileExists(fPath) { + return fPath + } + } + return "" // not found +} + +// FirstExists check multi paths and return first exists path. +func FirstExists(paths ...string) string { + return MatchFirst(paths, PathExists, "") +} + +// FirstExistsDir check multi paths and return first exists dir. +func FirstExistsDir(paths ...string) string { + return MatchFirst(paths, IsDir, "") +} + +// FirstExistsFile check multi paths and return first exists file. +func FirstExistsFile(paths ...string) string { + return MatchFirst(paths, IsFile, "") +} + +// MatchPaths given paths by custom mather func. +func MatchPaths(paths []string, matcher PathMatchFunc) []string { + var ret []string + for _, p := range paths { + if matcher(p) { + ret = append(ret, p) + } + } + return ret +} + +// MatchFirst filter paths by filter func and return first match path. +func MatchFirst(paths []string, matcher PathMatchFunc, defaultPath string) string { + for _, p := range paths { + if matcher(p) { + return p + } + } + return defaultPath +} + // SearchNameUp find file/dir name in dirPath or parent dirs, // return the name of directory path // @@ -57,7 +113,7 @@ func WalkDir(dir string, fn fs.WalkDirFunc) error { // Usage: // // files := fsutil.Glob("/path/to/dir/*.go") -func Glob(pattern string, fls ...comdef.StringMatchFunc) []string { +func Glob(pattern string, fls ...NameMatchFunc) []string { files, _ := filepath.Glob(pattern) if len(fls) == 0 || len(files) == 0 { return files diff --git a/vendor/github.com/gookit/goutil/fsutil/fsutil.go b/vendor/github.com/gookit/goutil/fsutil/fsutil.go index c4517ca18..5c7d2c2cc 100644 --- a/vendor/github.com/gookit/goutil/fsutil/fsutil.go +++ b/vendor/github.com/gookit/goutil/fsutil/fsutil.go @@ -2,8 +2,6 @@ package fsutil import ( - "io" - "net/http" "os" "path/filepath" "strings" @@ -11,77 +9,6 @@ import ( "github.com/gookit/goutil/internal/comfunc" ) -const ( - // MimeSniffLen sniff Length, use for detect file mime type - MimeSniffLen = 512 -) - -// OSTempFile create a temp file on os.TempDir() -// -// Usage: -// -// fsutil.OSTempFile("example.*.txt") -func OSTempFile(pattern string) (*os.File, error) { - return os.CreateTemp(os.TempDir(), pattern) -} - -// TempFile is like os.CreateTemp, but can custom temp dir. -// -// Usage: -// -// fsutil.TempFile("", "example.*.txt") -func TempFile(dir, pattern string) (*os.File, error) { - return os.CreateTemp(dir, pattern) -} - -// OSTempDir creates a new temp dir on os.TempDir and return the temp dir path -// -// Usage: -// -// fsutil.OSTempDir("example.*") -func OSTempDir(pattern string) (string, error) { - return os.MkdirTemp(os.TempDir(), pattern) -} - -// TempDir creates a new temp dir and return the temp dir path -// -// Usage: -// -// fsutil.TempDir("", "example.*") -// fsutil.TempDir("testdata", "example.*") -func TempDir(dir, pattern string) (string, error) { - return os.MkdirTemp(dir, pattern) -} - -// MimeType get File Mime Type name. eg "image/png" -func MimeType(path string) (mime string) { - file, err := os.Open(path) - if err != nil { - return - } - - return ReaderMimeType(file) -} - -// ReaderMimeType get the io.Reader mimeType -// -// Usage: -// -// file, err := os.Open(filepath) -// if err != nil { -// return -// } -// mime := ReaderMimeType(file) -func ReaderMimeType(r io.Reader) (mime string) { - var buf [MimeSniffLen]byte - n, _ := io.ReadFull(r, buf[:]) - if n == 0 { - return "" - } - - return http.DetectContentType(buf[:n]) -} - // JoinPaths elements, alias of filepath.Join() func JoinPaths(elem ...string) string { return filepath.Join(elem...) diff --git a/vendor/github.com/gookit/goutil/fsutil/info.go b/vendor/github.com/gookit/goutil/fsutil/info.go index 32ab28b96..ed55ca53f 100644 --- a/vendor/github.com/gookit/goutil/fsutil/info.go +++ b/vendor/github.com/gookit/goutil/fsutil/info.go @@ -8,6 +8,9 @@ import ( "github.com/gookit/goutil/internal/comfunc" ) +// DirPath get dir path from filepath, without last name. +func DirPath(fpath string) string { return filepath.Dir(fpath) } + // Dir get dir path from filepath, without last name. func Dir(fpath string) string { return filepath.Dir(fpath) } diff --git a/vendor/github.com/gookit/goutil/fsutil/info_nonwin.go b/vendor/github.com/gookit/goutil/fsutil/info_nonwin.go index 67c7cfece..364b5d2ae 100644 --- a/vendor/github.com/gookit/goutil/fsutil/info_nonwin.go +++ b/vendor/github.com/gookit/goutil/fsutil/info_nonwin.go @@ -9,6 +9,7 @@ import ( ) // Realpath returns the shortest path name equivalent to path by purely lexical processing. +// Will expand ~ to home dir, and join with workdir if path is relative path. func Realpath(pathStr string) string { pathStr = comfunc.ExpandHome(pathStr) diff --git a/vendor/github.com/gookit/goutil/fsutil/mime.go b/vendor/github.com/gookit/goutil/fsutil/mime.go new file mode 100644 index 000000000..b509960a8 --- /dev/null +++ b/vendor/github.com/gookit/goutil/fsutil/mime.go @@ -0,0 +1,40 @@ +package fsutil + +import ( + "io" + "net/http" + "os" +) + +// DetectMime detect file mime type. alias of MimeType() +func DetectMime(path string) string { + return MimeType(path) +} + +// MimeType get file mime type name. eg "image/png" +func MimeType(path string) (mime string) { + file, err := os.Open(path) + if err != nil { + return + } + return ReaderMimeType(file) +} + +// ReaderMimeType get the io.Reader mimeType +// +// Usage: +// +// file, err := os.Open(filepath) +// if err != nil { +// return +// } +// mime := ReaderMimeType(file) +func ReaderMimeType(r io.Reader) (mime string) { + var buf [MimeSniffLen]byte + n, _ := io.ReadFull(r, buf[:]) + if n == 0 { + return "" + } + + return http.DetectContentType(buf[:n]) +} diff --git a/vendor/github.com/gookit/goutil/fsutil/operate.go b/vendor/github.com/gookit/goutil/fsutil/operate.go index 5bf1e600a..5b20a88c5 100644 --- a/vendor/github.com/gookit/goutil/fsutil/operate.go +++ b/vendor/github.com/gookit/goutil/fsutil/operate.go @@ -39,7 +39,7 @@ func MkSubDirs(perm os.FileMode, parentDir string, subDirs ...string) error { return nil } -// MkParentDir quick create parent dir +// MkParentDir quick create parent dir for given path. func MkParentDir(fpath string) error { dirPath := filepath.Dir(fpath) if !IsDir(dirPath) { @@ -48,15 +48,70 @@ func MkParentDir(fpath string) error { return nil } +// ************************************************************ +// options for open file +// ************************************************************ + +// OpenOption for open file +type OpenOption struct { + // file open flag. see FsCWTFlags + Flag int + // file perm. see DefaultFilePerm + Perm os.FileMode +} + +// OpenOptionFunc for open/write file +type OpenOptionFunc func(*OpenOption) + +// NewOpenOption create a new OpenOption instance +// +// Defaults: +// - open flags: FsCWTFlags (override write) +// - file Perm: DefaultFilePerm +func NewOpenOption(optFns ...OpenOptionFunc) *OpenOption { + opt := &OpenOption{ + Flag: FsCWTFlags, + Perm: DefaultFilePerm, + } + + for _, fn := range optFns { + fn(opt) + } + return opt +} + +// OpenOptOrNew create a new OpenOption instance if opt is nil +func OpenOptOrNew(opt *OpenOption) *OpenOption { + if opt == nil { + return NewOpenOption() + } + return opt +} + +// WithFlag set file open flag +func WithFlag(flag int) OpenOptionFunc { + return func(opt *OpenOption) { + opt.Flag = flag + } +} + +// WithPerm set file perm +func WithPerm(perm os.FileMode) OpenOptionFunc { + return func(opt *OpenOption) { + opt.Perm = perm + } +} + // ************************************************************ // open/create files // ************************************************************ -// some commonly flag consts for open file +// some commonly flag consts for open file. const ( FsCWAFlags = os.O_CREATE | os.O_WRONLY | os.O_APPEND // create, append write-only FsCWTFlags = os.O_CREATE | os.O_WRONLY | os.O_TRUNC // create, override write-only FsCWFlags = os.O_CREATE | os.O_WRONLY // create, write-only + FsRWFlags = os.O_RDWR // read-write, dont create. FsRFlags = os.O_RDONLY // read-only ) @@ -65,13 +120,13 @@ const ( // Usage: // // file, err := OpenFile("path/to/file.txt", FsCWFlags, 0666) -func OpenFile(filepath string, flag int, perm os.FileMode) (*os.File, error) { - fileDir := path.Dir(filepath) +func OpenFile(filePath string, flag int, perm os.FileMode) (*os.File, error) { + fileDir := path.Dir(filePath) if err := os.MkdirAll(fileDir, DefaultDirPerm); err != nil { return nil, err } - file, err := os.OpenFile(filepath, flag, perm) + file, err := os.OpenFile(filePath, flag, perm) if err != nil { return nil, err } @@ -83,8 +138,8 @@ func OpenFile(filepath string, flag int, perm os.FileMode) (*os.File, error) { // Usage: // // file := MustOpenFile("path/to/file.txt", FsCWFlags, 0666) -func MustOpenFile(filepath string, flag int, perm os.FileMode) *os.File { - file, err := OpenFile(filepath, flag, perm) +func MustOpenFile(filePath string, flag int, perm os.FileMode) *os.File { + file, err := OpenFile(filePath, flag, perm) if err != nil { panic(err) } @@ -173,6 +228,11 @@ func MustRemove(fPath string) { // NOTICE: will ignore error func QuietRemove(fPath string) { _ = os.Remove(fPath) } +// SafeRemoveAll removes path and any children it contains. will ignore error +func SafeRemoveAll(path string) { + _ = os.RemoveAll(path) +} + // RmIfExist removes the named file or (empty) directory on exists. func RmIfExist(fPath string) error { return DeleteIfExist(fPath) } @@ -202,6 +262,11 @@ func RemoveSub(dirPath string, fns ...FilterFunc) error { if err := RemoveSub(fPath, fns...); err != nil { return err } + + // skip rm not empty subdir + if !IsEmptyDir(fPath) { + return nil + } } return os.Remove(fPath) }, fns...) diff --git a/vendor/github.com/gookit/goutil/fsutil/opread.go b/vendor/github.com/gookit/goutil/fsutil/opread.go index 23f552332..8cbb0f234 100644 --- a/vendor/github.com/gookit/goutil/fsutil/opread.go +++ b/vendor/github.com/gookit/goutil/fsutil/opread.go @@ -6,6 +6,8 @@ import ( "io" "os" "text/scanner" + + "github.com/gookit/goutil/basefn" ) // NewIOReader instance by input file path or io.Reader @@ -70,20 +72,27 @@ func ReadStringOrErr(in any) (string, error) { } // ReadAll read contents from path or io.Reader, will panic on in type error -func ReadAll(in any) []byte { return GetContents(in) } +func ReadAll(in any) []byte { return MustRead(in) } // GetContents read contents from path or io.Reader, will panic on in type error -func GetContents(in any) []byte { - r, err := NewIOReader(in) - if err != nil { - panic(err) - } - return MustReadReader(r) +func GetContents(in any) []byte { return MustRead(in) } + +// MustRead read contents from path or io.Reader, will panic on in type error +func MustRead(in any) []byte { + return basefn.Must(ReadOrErr(in)) } // ReadOrErr read contents from path or io.Reader, will panic on in type error func ReadOrErr(in any) ([]byte, error) { r, err := NewIOReader(in) + defer func() { + if r != nil { + if file, ok := r.(*os.File); ok { + err = file.Close() + } + } + }() + if err != nil { return nil, err } @@ -102,7 +111,8 @@ func ReadExistFile(filePath string) []byte { return nil } -// TextScanner from filepath or io.Reader, will panic on in type error +// TextScanner from filepath or io.Reader, will panic on in type error. +// Will scan parse text to tokens: Ident, Int, Float, Char, String, RawString, Comment, etc. // // Usage: // @@ -122,7 +132,8 @@ func TextScanner(in any) *scanner.Scanner { return &s } -// LineScanner create from filepath or io.Reader +// LineScanner create from filepath or io.Reader, will panic on in type error. +// Will scan and parse text to lines. // // s := fsutil.LineScanner("/path/to/file") // for s.Scan() { diff --git a/vendor/github.com/gookit/goutil/fsutil/opwrite.go b/vendor/github.com/gookit/goutil/fsutil/opwrite.go index d264a3ca0..64e3a1bac 100644 --- a/vendor/github.com/gookit/goutil/fsutil/opwrite.go +++ b/vendor/github.com/gookit/goutil/fsutil/opwrite.go @@ -7,13 +7,73 @@ import ( "github.com/gookit/goutil/basefn" ) +// ************************************************************ +// temp file or dir +// ************************************************************ + +// OSTempFile create a temp file on os.TempDir() +// +// Usage: +// +// fsutil.OSTempFile("example.*.txt") +func OSTempFile(pattern string) (*os.File, error) { + return os.CreateTemp(os.TempDir(), pattern) +} + +// TempFile is like os.CreateTemp, but can custom temp dir. +// +// Usage: +// +// // create temp file on os.TempDir() +// fsutil.TempFile("", "example.*.txt") +// // create temp file on "testdata" dir +// fsutil.TempFile("testdata", "example.*.txt") +func TempFile(dir, pattern string) (*os.File, error) { + return os.CreateTemp(dir, pattern) +} + +// OSTempDir creates a new temp dir on os.TempDir and return the temp dir path +// +// Usage: +// +// fsutil.OSTempDir("example.*") +func OSTempDir(pattern string) (string, error) { + return os.MkdirTemp(os.TempDir(), pattern) +} + +// TempDir creates a new temp dir and return the temp dir path +// +// Usage: +// +// fsutil.TempDir("", "example.*") +// fsutil.TempDir("testdata", "example.*") +func TempDir(dir, pattern string) (string, error) { + return os.MkdirTemp(dir, pattern) +} + // ************************************************************ // write, copy files // ************************************************************ -// PutContents create file and write contents to file at once. +// MustSave create file and write contents to file, panic on error. // // data type allow: string, []byte, io.Reader +// default option see NewOpenOption() +func MustSave(filePath string, data any, optFns ...OpenOptionFunc) { + basefn.MustOK(SaveFile(filePath, data, optFns...)) +} + +// SaveFile create file and write contents to file. will auto create dir. +// +// default option see NewOpenOption() +func SaveFile(filePath string, data any, optFns ...OpenOptionFunc) error { + opt := NewOpenOption(optFns...) + return WriteFile(filePath, data, opt.Perm, opt.Flag) +} + +// PutContents create file and write contents to file at once. +// +// data type allow: string, []byte, io.Reader. will auto create dir. // // Tip: file flag default is FsCWTFlags (override write) // @@ -25,7 +85,6 @@ func PutContents(filePath string, data any, fileFlag ...int) (int, error) { if err != nil { return 0, err } - return WriteOSFile(f, data) } @@ -99,3 +158,21 @@ func MustCopyFile(srcPath, dstPath string) { panic(err) } } + +// UpdateContents read file contents, call handleFn(contents) handle, then write updated contents to file +func UpdateContents(filePath string, handleFn func(bs []byte) []byte) error { + osFile, err := os.OpenFile(filePath, os.O_RDWR|os.O_TRUNC, 0600) + if err != nil { + return err + } + defer osFile.Close() + + // read file contents + if bs, err1 := io.ReadAll(osFile); err1 == nil { + bs = handleFn(bs) + _, err = osFile.Write(bs) + } else { + err = err1 + } + return err +} diff --git a/vendor/github.com/gookit/goutil/func.go b/vendor/github.com/gookit/goutil/func.go index 0573f1d10..285e83fac 100644 --- a/vendor/github.com/gookit/goutil/func.go +++ b/vendor/github.com/gookit/goutil/func.go @@ -1,11 +1,6 @@ package goutil -import "github.com/gookit/goutil/stdutil" - -// FuncName get func name -func FuncName(f any) string { - return stdutil.FuncName(f) -} +import "fmt" // Go is a basic promise implementation: it wraps calls a function in a goroutine // and returns a channel which will later return the function's return value. @@ -35,3 +30,53 @@ func CallOrElse(cond bool, okFn, elseFn ErrFunc) error { } return elseFn() } + +// SafeRun sync run a func. If the func panics, the panic value is returned as an error. +func SafeRun(fn func()) (err error) { + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else { + err = fmt.Errorf("%v", r) + } + } + }() + fn() + return nil +} + +// SafeRun sync run a func with error. +// If the func panics, the panic value is returned as an error. +func SafeRunWithError(fn func() error) (err error) { + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else { + err = fmt.Errorf("%v", r) + } + } + }() + return fn() +} + +// SafeGo async run a func. +// If the func panics, the panic value will be handle by errHandler. +func SafeGo(fn func(), errHandler func(error)) { + go func() { + if err := SafeRun(fn); err != nil { + errHandler(err) + } + }() +} + +// SafeGoWithError async run a func with error. +// If the func panics, the panic value will be handle by errHandler. +func SafeGoWithError(fn func() error, errHandler func(error)) { + go func() { + if err := SafeRunWithError(fn); err != nil { + errHandler(err) + } + }() +} diff --git a/vendor/github.com/gookit/goutil/goinfo/README.md b/vendor/github.com/gookit/goutil/goinfo/README.md new file mode 100644 index 000000000..2df63a6e0 --- /dev/null +++ b/vendor/github.com/gookit/goutil/goinfo/README.md @@ -0,0 +1,34 @@ +# GoInfo + + `goutil/goinfo` provide some useful info for golang. + +> Github: https://github.com/gookit/goutil + +## Install + +```bash +go get github.com/gookit/goutil/goinfo +``` + +## Go docs + +- [Go docs](https://pkg.go.dev/github.com/gookit/goutil) + +## Usage + +```go +gover := goinfo.GoVersion() // eg: "1.15.6" + +``` + +## Testings + +```shell +go test -v ./goinfo/... +``` + +Test limit by regexp: + +```shell +go test -v -run ^TestSetByKeys ./goinfo/... +``` diff --git a/vendor/github.com/gookit/goutil/stdutil/gofunc.go b/vendor/github.com/gookit/goutil/goinfo/gofunc.go similarity index 60% rename from vendor/github.com/gookit/goutil/stdutil/gofunc.go rename to vendor/github.com/gookit/goutil/goinfo/gofunc.go index 6a2be9c29..a0d5d2a38 100644 --- a/vendor/github.com/gookit/goutil/stdutil/gofunc.go +++ b/vendor/github.com/gookit/goutil/goinfo/gofunc.go @@ -1,20 +1,21 @@ -package stdutil +package goinfo import ( "reflect" "runtime" "strings" + "unicode" "github.com/gookit/goutil/strutil" ) // FullFcName struct. type FullFcName struct { - // FullName eg: github.com/gookit/goutil/stdutil.PanicIf + // FullName eg: "github.com/gookit/goutil/goinfo.PanicIf" FullName string - pkgPath string - pkgName string - funcName string + pkgPath string // "github.com/gookit/goutil/goinfo" + pkgName string // "goinfo" + funcName string // "PanicIf" } // Parse the full func name. @@ -28,17 +29,16 @@ func (ffn *FullFcName) Parse() { ffn.pkgPath = ffn.FullName[:i+1] // spilt get pkg and func name ffn.pkgName, ffn.funcName = strutil.MustCut(ffn.FullName[i+1:], ".") - ffn.pkgPath += ffn.pkgName } -// PkgPath string get. eg: github.com/gookit/goutil/stdutil +// PkgPath string get. eg: github.com/gookit/goutil/goinfo func (ffn *FullFcName) PkgPath() string { ffn.Parse() return ffn.pkgPath } -// PkgName string get. eg: stdutil +// PkgName string get. eg: goinfo func (ffn *FullFcName) PkgName() string { ffn.Parse() return ffn.pkgName @@ -50,7 +50,7 @@ func (ffn *FullFcName) FuncName() string { return ffn.funcName } -// String get full func name string. +// String get full func name string, pkg path and func name. func (ffn *FullFcName) String() string { return ffn.FullName } @@ -59,13 +59,16 @@ func (ffn *FullFcName) String() string { // // eg: // -// // OUTPUT: github.com/gookit/goutil/stdutil.PanicIf -// stdutil.FuncName(stdutil.PkgName) +// // OUTPUT: github.com/gookit/goutil/goinfo.PkgName +// goinfo.FuncName(goinfo.PkgName) func FuncName(fn any) string { return runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name() } // CutFuncName get pkg path and short func name +// eg: +// +// "github.com/gookit/goutil/goinfo.FuncName" => [github.com/gookit/goutil/goinfo, FuncName] func CutFuncName(fullFcName string) (pkgPath, shortFnName string) { ffn := FullFcName{FullName: fullFcName} return ffn.PkgPath(), ffn.FuncName() @@ -75,12 +78,13 @@ func CutFuncName(fullFcName string) (pkgPath, shortFnName string) { // // Usage: // -// fullFcName := stdutil.FuncName(fn) -// pgkName := stdutil.PkgName(fullFcName) +// fullFcName := goinfo.FuncName(fn) +// pgkName := goinfo.PkgName(fullFcName) func PkgName(fullFcName string) string { for { lastPeriod := strings.LastIndex(fullFcName, ".") lastSlash := strings.LastIndex(fullFcName, "/") + if lastPeriod > lastSlash { fullFcName = fullFcName[:lastPeriod] } else { @@ -89,3 +93,21 @@ func PkgName(fullFcName string) string { } return fullFcName } + +// GoodFuncName reports whether the function name is a valid identifier. +func GoodFuncName(name string) bool { + if name == "" { + return false + } + + for i, r := range name { + switch { + case r == '_': + case i == 0 && !unicode.IsLetter(r): + return false + case !unicode.IsLetter(r) && !unicode.IsDigit(r): + return false + } + } + return true +} diff --git a/vendor/github.com/gookit/goutil/goinfo/goinfo.go b/vendor/github.com/gookit/goutil/goinfo/goinfo.go new file mode 100644 index 000000000..ff5dd3a1c --- /dev/null +++ b/vendor/github.com/gookit/goutil/goinfo/goinfo.go @@ -0,0 +1,78 @@ +// Package goinfo provide some standard util functions for go. +package goinfo + +import ( + "errors" + "os/exec" + "regexp" + "runtime" + "strings" +) + +// GoVersion get go runtime version. eg: "1.18.2" +func GoVersion() string { + return runtime.Version()[2:] +} + +// GoInfo define +// +// On os by: +// +// go env GOVERSION GOOS GOARCH +// go version // "go version go1.19 darwin/amd64" +type GoInfo struct { + Version string + GoOS string + Arch string +} + +// match "go version go1.19 darwin/amd64" +var goVerRegex = regexp.MustCompile(`\sgo([\d.]+)\s(\w+)/(\w+)`) + +// ParseGoVersion get info by parse `go version` results. +// +// Examples: +// +// line, err := sysutil.ExecLine("go version") +// if err != nil { +// return err +// } +// +// info, err := goinfo.ParseGoVersion() +// dump.P(info) +func ParseGoVersion(line string) (*GoInfo, error) { + // eg: [" go1.19 darwin/amd64", "1.19", "darwin", "amd64"] + lines := goVerRegex.FindStringSubmatch(line) + if len(lines) != 4 { + return nil, errors.New("input go version info is invalid") + } + + info := &GoInfo{ + Version: strings.TrimPrefix(lines[1], "go"), + } + info.GoOS = lines[2] + info.Arch = lines[3] + + return info, nil +} + +// OsGoInfo fetch and parse +func OsGoInfo() (*GoInfo, error) { + cmdArgs := []string{"env", "GOVERSION", "GOOS", "GOARCH"} + bs, err := exec.Command("go", cmdArgs...).Output() + if err != nil { + return nil, err + } + + lines := strings.Split(strings.TrimSpace(string(bs)), "\n") + if len(lines) != len(cmdArgs)-1 { + return nil, errors.New("returns go info is not full") + } + + info := &GoInfo{} + info.Version = strings.TrimPrefix(lines[0], "go") + info.GoOS = lines[1] + info.Arch = lines[2] + + return info, nil +} diff --git a/vendor/github.com/gookit/goutil/stdutil/stack.go b/vendor/github.com/gookit/goutil/goinfo/stack.go similarity index 90% rename from vendor/github.com/gookit/goutil/stdutil/stack.go rename to vendor/github.com/gookit/goutil/goinfo/stack.go index 701d1be74..c5c11bbc8 100644 --- a/vendor/github.com/gookit/goutil/stdutil/stack.go +++ b/vendor/github.com/gookit/goutil/goinfo/stack.go @@ -1,10 +1,12 @@ -package stdutil +package goinfo import ( "path" "runtime" "strconv" "strings" + + "github.com/gookit/goutil/basefn" ) // some commonly consts @@ -42,15 +44,11 @@ func GetCallStacks(all bool) []byte { // // returns: // -// github.com/gookit/goutil/stdutil_test.someFunc2(),stack_test.go:26 +// github.com/gookit/goutil/goinfo_test.someFunc2(),stack_test.go:26 func GetCallerInfo(skip int) string { skip++ // ignore current func cs := GetCallersInfo(skip, skip+1) - - if len(cs) > 0 { - return cs[0] - } - return "" + return basefn.FirstOr(cs, "") } // SimpleCallersInfo returns an array of strings containing @@ -62,6 +60,7 @@ func SimpleCallersInfo(skip, num int) []string { // GetCallersInfo returns an array of strings containing // the func name, file and line number of each stack frame leading. +// // NOTICE: max should > skip func GetCallersInfo(skip, max int) []string { var ( @@ -93,7 +92,7 @@ func GetCallersInfo(skip, max int) []string { if strings.ContainsRune(file, '/') { name = fc.Name() file = path.Base(file) - // eg: github.com/gookit/goutil/stdutil_test.someFunc2(),stack_test.go:26 + // eg: github.com/gookit/goutil/goinfo_test.someFunc2(),stack_test.go:26 callers = append(callers, name+"(),"+file+":"+strconv.Itoa(line)) } diff --git a/vendor/github.com/gookit/goutil/goutil.go b/vendor/github.com/gookit/goutil/goutil.go index 6298c9f74..2394b822f 100644 --- a/vendor/github.com/gookit/goutil/goutil.go +++ b/vendor/github.com/gookit/goutil/goutil.go @@ -5,17 +5,24 @@ package goutil import ( "fmt" - "github.com/gookit/goutil/stdutil" + "github.com/gookit/goutil/basefn" + "github.com/gookit/goutil/goinfo" + "github.com/gookit/goutil/structs" ) -// Value alias of stdutil.Value -type Value = stdutil.Value +// Value alias of structs.Value +type Value = structs.Value // Panicf format panic message use fmt.Sprintf func Panicf(format string, v ...any) { panic(fmt.Sprintf(format, v...)) } +// PanicIf if cond = true, panics with error message +func PanicIf(cond bool, fmtAndArgs ...any) { + basefn.PanicIf(cond, fmtAndArgs...) +} + // PanicIfErr if error is not empty, will panic func PanicIfErr(err error) { if err != nil { @@ -45,14 +52,19 @@ func Must[T any](v T, err error) T { return v } -// PkgName get current package name. alias of stdutil.PkgName() +// FuncName get func name +func FuncName(f any) string { + return goinfo.FuncName(f) +} + +// PkgName get current package name. alias of goinfo.PkgName() // // Usage: // // funcName := goutil.FuncName(fn) // pgkName := goutil.PkgName(funcName) func PkgName(funcName string) string { - return stdutil.PkgName(funcName) + return goinfo.PkgName(funcName) } // ErrOnFail return input error on cond is false, otherwise return nil diff --git a/vendor/github.com/gookit/goutil/group.go b/vendor/github.com/gookit/goutil/group.go index 90a3204da..0038d3d31 100644 --- a/vendor/github.com/gookit/goutil/group.go +++ b/vendor/github.com/gookit/goutil/group.go @@ -4,46 +4,21 @@ import ( "context" "github.com/gookit/goutil/structs" - "golang.org/x/sync/errgroup" + "github.com/gookit/goutil/syncs" ) // ErrGroup is a collection of goroutines working on subtasks that // are part of the same overall task. -// -// Refers: -// -// https://github.com/neilotoole/errgroup -// https://github.com/fatih/semgroup -type ErrGroup struct { - *errgroup.Group -} +type ErrGroup = syncs.ErrGroup // NewCtxErrGroup instance func NewCtxErrGroup(ctx context.Context, limit ...int) (*ErrGroup, context.Context) { - egg, ctx1 := errgroup.WithContext(ctx) - if len(limit) > 0 && limit[0] > 0 { - egg.SetLimit(limit[0]) - } - - eg := &ErrGroup{Group: egg} - return eg, ctx1 + return syncs.NewCtxErrGroup(ctx, limit...) } // NewErrGroup instance func NewErrGroup(limit ...int) *ErrGroup { - eg := &ErrGroup{Group: new(errgroup.Group)} - - if len(limit) > 0 && limit[0] > 0 { - eg.SetLimit(limit[0]) - } - return eg -} - -// Add one or more handler at once -func (g *ErrGroup) Add(handlers ...func() error) { - for _, handler := range handlers { - g.Go(handler) - } + return syncs.NewErrGroup(limit...) } // RunFn func diff --git a/vendor/github.com/gookit/goutil/internal/checkfn/check.go b/vendor/github.com/gookit/goutil/internal/checkfn/check.go new file mode 100644 index 000000000..b6c562986 --- /dev/null +++ b/vendor/github.com/gookit/goutil/internal/checkfn/check.go @@ -0,0 +1,78 @@ +package checkfn + +import ( + "fmt" + "reflect" + "strings" + + "github.com/gookit/goutil/reflects" +) + +// IsNil value check +func IsNil(v any) bool { + if v == nil { + return true + } + return reflects.IsNil(reflect.ValueOf(v)) +} + +// IsEmpty value check +func IsEmpty(v any) bool { + if v == nil { + return true + } + return reflects.IsEmpty(reflect.ValueOf(v)) +} + +// Contains try loop over the data check if the data includes the element. +// +// data allow types: string, map, array, slice +// +// map - check key exists +// string - check sub-string exists +// array,slice - check sub-element exists +// +// Returns: +// - valid: data is valid +// - found: element was found +// +// return (false, false) if impossible. +// return (true, false) if element was not found. +// return (true, true) if element was found. +func Contains(data, elem any) (valid, found bool) { + if data == nil { + return false, false + } + + dataRv := reflect.ValueOf(data) + dataRt := reflect.TypeOf(data) + dataKind := dataRt.Kind() + + // string + if dataKind == reflect.String { + return true, strings.Contains(dataRv.String(), fmt.Sprint(elem)) + } + + // map + if dataKind == reflect.Map { + mapKeys := dataRv.MapKeys() + for i := 0; i < len(mapKeys); i++ { + if reflects.IsEqual(mapKeys[i].Interface(), elem) { + return true, true + } + } + return true, false + } + + // array, slice - other return false + if dataKind != reflect.Slice && dataKind != reflect.Array { + return false, false + } + + for i := 0; i < dataRv.Len(); i++ { + if reflects.IsEqual(dataRv.Index(i).Interface(), elem) { + return true, true + } + } + return true, false +} diff --git a/vendor/github.com/gookit/goutil/internal/comfunc/README.md b/vendor/github.com/gookit/goutil/internal/comfunc/README.md new file mode 100644 index 000000000..3057ef9e9 --- /dev/null +++ b/vendor/github.com/gookit/goutil/internal/comfunc/README.md @@ -0,0 +1,3 @@ +# common func for internal use + +- don't depend on other external packages \ No newline at end of file diff --git a/vendor/github.com/gookit/goutil/internal/comfunc/comfunc.go b/vendor/github.com/gookit/goutil/internal/comfunc/comfunc.go index bd9e7525c..8a3206131 100644 --- a/vendor/github.com/gookit/goutil/internal/comfunc/comfunc.go +++ b/vendor/github.com/gookit/goutil/internal/comfunc/comfunc.go @@ -26,90 +26,14 @@ func Environ() map[string]string { return envMap } -// parse env value, allow: -// -// only key - "${SHELL}" -// with default - "${NotExist | defValue}" -// multi key - "${GOPATH}/${APP_ENV | prod}/dir" -// -// Notice: -// -// must add "?" - To ensure that there is no greedy match -// var envRegex = regexp.MustCompile(`\${[\w-| ]+}`) -var envRegex = regexp.MustCompile(`\${.+?}`) - -// ParseEnvVar parse ENV var value from input string, support default value. -// -// Format: -// -// ${var_name} Only var name -// ${var_name | default} With default value -// -// Usage: -// -// comfunc.ParseEnvVar("${ APP_NAME }") -// comfunc.ParseEnvVar("${ APP_ENV | dev }") -func ParseEnvVar(val string, getFn func(string) string) (newVal string) { - if !strings.Contains(val, "${") { - return val - } - - // default use os.Getenv - if getFn == nil { - getFn = os.Getenv - } - - var name, def string - return envRegex.ReplaceAllStringFunc(val, func(eVar string) string { - // eVar like "${NotExist|defValue}", first remove "${" and "}", then split it - ss := strings.SplitN(eVar[2:len(eVar)-1], "|", 2) - - // with default value. ${NotExist|defValue} - if len(ss) == 2 { - name, def = strings.TrimSpace(ss[0]), strings.TrimSpace(ss[1]) - } else { - name = strings.TrimSpace(ss[0]) - } - - // get ENV value by name - eVal := getFn(name) - if eVal == "" { - eVal = def - } - return eVal - }) -} - -// FormatTplAndArgs message -func FormatTplAndArgs(fmtAndArgs []any) string { - if len(fmtAndArgs) == 0 || fmtAndArgs == nil { - return "" - } - - ln := len(fmtAndArgs) - first := fmtAndArgs[0] - - if ln == 1 { - if msgAsStr, ok := first.(string); ok { - return msgAsStr - } - return fmt.Sprintf("%+v", first) - } - - // is template string. - if tplStr, ok := first.(string); ok { - return fmt.Sprintf(tplStr, fmtAndArgs[1:]...) - } - return fmt.Sprint(fmtAndArgs...) -} - var ( - // TIP: extend unit d,w - // time.ParseDuration() is not supported. eg: "1d", "2w" + // TIP: extend unit d,w. eg: "1d", "2w" + // time.ParseDuration() is max support hour "h". durStrReg = regexp.MustCompile(`^(-?\d+)(ns|us|µs|ms|s|m|h|d|w)$`) - // match long duration string, such as "1hour", "2hours", "3minutes", "4mins", "5days", "1weeks" + + // match long duration string. eg: "1hour", "2hours", "3minutes", "4mins", "5days", "1weeks", "1month" // time.ParseDuration() is not supported. - durStrRegL = regexp.MustCompile(`^(-?\d+)([a-zA-Z]{3,})$`) + durStrRegL = regexp.MustCompile(`^(-?\d+)([hdmsw][a-zA-Z]{2,8})$`) ) // IsDuration check the string is a duration string. @@ -153,6 +77,10 @@ func ToDuration(s string) (time.Duration, error) { // convert to short unit switch unit { + case "month", "months": + // max unit is hour, so need convert by 24 * 30 * n + n, _ := strconv.Atoi(num) + s = strconv.Itoa(n*24*30) + "h" case "week", "weeks": // max unit is hour, so need convert by 24 * 7 * n n, _ := strconv.Atoi(num) diff --git a/vendor/github.com/gookit/goutil/internal/comfunc/convert.go b/vendor/github.com/gookit/goutil/internal/comfunc/convert.go index 430882c17..c3a015e82 100644 --- a/vendor/github.com/gookit/goutil/internal/comfunc/convert.go +++ b/vendor/github.com/gookit/goutil/internal/comfunc/convert.go @@ -37,3 +37,26 @@ func StrToBool(s string) (bool, error) { return false, fmt.Errorf("'%s' cannot convert to bool", s) } + +// FormatWithArgs format message with args +func FormatWithArgs(fmtAndArgs []any) string { + ln := len(fmtAndArgs) + if ln == 0 { + return "" + } + + first := fmtAndArgs[0] + + if ln == 1 { + if msgAsStr, ok := first.(string); ok { + return msgAsStr + } + return fmt.Sprintf("%+v", first) + } + + // is template string. + if tplStr, ok := first.(string); ok { + return fmt.Sprintf(tplStr, fmtAndArgs[1:]...) + } + return fmt.Sprint(fmtAndArgs...) +} diff --git a/vendor/github.com/gookit/goutil/internal/varexpr/varexpr.go b/vendor/github.com/gookit/goutil/internal/varexpr/varexpr.go new file mode 100644 index 000000000..3c400f9cb --- /dev/null +++ b/vendor/github.com/gookit/goutil/internal/varexpr/varexpr.go @@ -0,0 +1,145 @@ +// Package varexpr provides some commonly ENV var parse functions. +// +// parse env value, allow expressions: +// +// ${VAR_NAME} Only var name +// ${VAR_NAME | default} With default value, if value is empty. +// ${VAR_NAME | ?error} With error on value is empty. +// +// Examples: +// +// only key - "${SHELL}" +// with default - "${NotExist | defValue}" +// multi key - "${GOPATH}/${APP_ENV | prod}/dir" +package varexpr + +import ( + "errors" + "os" + "regexp" + "strings" +) + +// SepChar separator char +const SepChar = "|" + +// ParseOptFn option func +type ParseOptFn func(o *ParseOpts) + +// ParseOpts parse options for ParseValue +type ParseOpts struct { + // Getter Env value provider func. + Getter func(string) string + // ParseFn custom parse expr func. expr like "${SHELL}" "${NotExist|defValue}" + ParseFn func(string) (string, error) + // Regexp custom expression regex. + Regexp *regexp.Regexp + // Keyword check chars for expression. default is "${" + Keyword string +} + +// must add "?" - To ensure that there is no greedy match +var envRegex = regexp.MustCompile(`\${.+?}`) +var std = New() + +// Parse parse ENV var value from input string, support default value. +// +// Format: +// +// ${var_name} Only var name +// ${var_name | default} With default value +// ${var_name | ?error} With error on value is empty. +func Parse(val string) (string, error) { + return std.Parse(val) +} + +// SafeParse parse ENV var value from input string, support default value. +func SafeParse(val string) string { + s, _ := std.Parse(val) + return s +} + +// ParseWith parse ENV var value from input string, support default value. +func ParseWith(val string, optFns ...ParseOptFn) (string, error) { + return New(optFns...).Parse(val) +} + +// Parser parse ENV var value from input string, support default value. +type Parser struct { + ParseOpts +} + +// New create a new Parser +func New(optFns ...ParseOptFn) *Parser { + opts := &ParseOpts{ + Getter: os.Getenv, + Regexp: envRegex, + Keyword: "${", + } + for _, fn := range optFns { + fn(opts) + } + + return &Parser{ParseOpts: *opts} +} + +// Parse parse ENV var value from input string, support default value. +// +// Format: +// +// ${var_name} Only var name +// ${var_name | default} With default value +// ${var_name | ?error} With error on value is empty. +func (p *Parser) Parse(val string) (newVal string, err error) { + if p.Regexp == nil { + p.Regexp = envRegex + } + + if p.Keyword != "" && !strings.Contains(val, p.Keyword) { + return val, nil + } + + // parse expression + newVal = p.Regexp.ReplaceAllStringFunc(val, func(s string) string { + if err != nil { + return s + } + s, err = p.parseOne(s) + return s + }) + return +} + +// parse one node expression. +func (p *Parser) parseOne(eVar string) (val string, err error) { + if p.ParseFn != nil { + return p.ParseFn(eVar) + } + + // eVar like "${NotExist|defValue}", first remove "${" and "}", then split it + ss := strings.SplitN(eVar[2:len(eVar)-1], SepChar, 2) + var name, def string + + // with default value. ${NotExist|defValue} + if len(ss) == 2 { + name, def = strings.TrimSpace(ss[0]), strings.TrimSpace(ss[1]) + } else { + name = strings.TrimSpace(ss[0]) + } + + // get ENV value by name + val = p.Getter(name) + if val == "" && def != "" { + // check def is "?error" + if def[0] == '?' { + msg := "value is required for var: " + name + if len(def) > 1 { + msg = def[1:] + } + err = errors.New(msg) + } else { + val = def + } + } + return +} diff --git a/vendor/github.com/gookit/goutil/jsonutil/encoding.go b/vendor/github.com/gookit/goutil/jsonutil/encoding.go new file mode 100644 index 000000000..da05a3246 --- /dev/null +++ b/vendor/github.com/gookit/goutil/jsonutil/encoding.go @@ -0,0 +1,64 @@ +package jsonutil + +import ( + "bytes" + "encoding/json" + "io" +) + +// MustString encode data to json string, will panic on error +func MustString(v any) string { + bs, err := json.Marshal(v) + if err != nil { + panic(err) + } + return string(bs) +} + +// Encode data to json bytes. alias of json.Marshal +func Encode(v any) ([]byte, error) { + return json.Marshal(v) +} + +// EncodePretty encode data to pretty JSON bytes. +func EncodePretty(v any) ([]byte, error) { + return json.MarshalIndent(v, "", " ") +} + +// EncodeString encode data to JSON string. +func EncodeString(v any) (string, error) { + bs, err := json.MarshalIndent(v, "", " ") + return string(bs), err +} + +// EncodeToWriter encode data to json and write to writer. +func EncodeToWriter(v any, w io.Writer) error { + return json.NewEncoder(w).Encode(v) +} + +// EncodeUnescapeHTML data to json bytes. will close escape HTML +func EncodeUnescapeHTML(v any) ([]byte, error) { + buf := &bytes.Buffer{} + enc := json.NewEncoder(buf) + enc.SetEscapeHTML(false) + + if err := enc.Encode(v); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// Decode json bytes to data ptr. alias of json.Unmarshal +func Decode(bts []byte, ptr any) error { + return json.Unmarshal(bts, ptr) +} + +// DecodeString json string to data ptr. +func DecodeString(str string, ptr any) error { + return json.Unmarshal([]byte(str), ptr) +} + +// DecodeReader decode JSON from io reader. +func DecodeReader(r io.Reader, ptr any) error { + return json.NewDecoder(r).Decode(ptr) +} diff --git a/vendor/github.com/gookit/goutil/jsonutil/jsonbuild.go b/vendor/github.com/gookit/goutil/jsonutil/jsonbuild.go new file mode 100644 index 000000000..6359500b9 --- /dev/null +++ b/vendor/github.com/gookit/goutil/jsonutil/jsonbuild.go @@ -0,0 +1,21 @@ +package jsonutil + +/* +TODO json build +type JsonBuilder struct { + Indent string + // mu sync.Mutex + // cfg *CConfig + buf bytes.Buffer + out io.Writer +} + +// AddField add field to json +func (b *JsonBuilder) AddField(key string, value any) *JsonBuilder { + b.buf.WriteString(`,"`) + b.buf.WriteString(key) + b.buf.WriteString(`":`) + b.encode(value) + return b +} +*/ diff --git a/vendor/github.com/gookit/goutil/jsonutil/jsonutil.go b/vendor/github.com/gookit/goutil/jsonutil/jsonutil.go index c7d392d8e..8d4c15ecd 100644 --- a/vendor/github.com/gookit/goutil/jsonutil/jsonutil.go +++ b/vendor/github.com/gookit/goutil/jsonutil/jsonutil.go @@ -4,7 +4,6 @@ package jsonutil import ( "bytes" "encoding/json" - "io" "os" "regexp" "strings" @@ -13,7 +12,7 @@ import ( // WriteFile write data to JSON file func WriteFile(filePath string, data any) error { - jsonBytes, err := Encode(data) + jsonBytes, err := json.Marshal(data) if err != nil { return err } @@ -46,71 +45,35 @@ func Pretty(v any) (string, error) { return string(out), err } -// Encode data to json bytes. -func Encode(v any) ([]byte, error) { - return json.Marshal(v) -} - -// EncodePretty encode pretty JSON data to json bytes. -func EncodePretty(v any) ([]byte, error) { - return json.MarshalIndent(v, "", " ") -} - -// EncodeToWriter encode data to writer. -func EncodeToWriter(v any, w io.Writer) error { - return json.NewEncoder(w).Encode(v) -} - -// EncodeUnescapeHTML data to json bytes. will close escape HTML -func EncodeUnescapeHTML(v any) ([]byte, error) { - buf := &bytes.Buffer{} - enc := json.NewEncoder(buf) - enc.SetEscapeHTML(false) - - if err := enc.Encode(v); err != nil { - return nil, err +// MustPretty data to JSON string, will panic on error +func MustPretty(v any) string { + out, err := json.MarshalIndent(v, "", " ") + if err != nil { + panic(err) } - - return buf.Bytes(), nil -} - -// Decode json bytes to data ptr. -func Decode(bts []byte, ptr any) error { - return json.Unmarshal(bts, ptr) -} - -// DecodeString json string to data ptr. -func DecodeString(str string, ptr any) error { - return json.Unmarshal([]byte(str), ptr) -} - -// DecodeReader decode JSON from io reader. -func DecodeReader(r io.Reader, ptr any) error { - return json.NewDecoder(r).Decode(ptr) + return string(out) } // Mapping src data(map,struct) to dst struct use json tags. // // On src, dst both is struct, equivalent to merging two structures (src should be a subset of dsc) func Mapping(src, dst any) error { - bts, err := Encode(src) + bts, err := json.Marshal(src) if err != nil { return err } return Decode(bts, dst) } -// IsJSON check if the string is valid JSON. (Note: uses json.Unmarshal) +// IsJSON check if the string is valid JSON. (Note: uses json.Valid) func IsJSON(s string) bool { if s == "" { return false } - - var js json.RawMessage - return json.Unmarshal([]byte(s), &js) == nil + return json.Valid([]byte(s)) } -// IsJSONFast simple and fast check input string is valid JSON. +// IsJSONFast simple and fast check input is valid JSON array or object. func IsJSONFast(s string) bool { ln := len(s) if ln < 2 { @@ -129,6 +92,32 @@ func IsJSONFast(s string) bool { return s[0] == '[' && s[ln-1] == ']' } +// IsArray check if the string is valid JSON array. +func IsArray(s string) bool { + ln := len(s) + if ln < 2 { + return false + } + return s[0] == '[' && s[ln-1] == ']' +} + +// IsObject check if the string is valid JSON object. +func IsObject(s string) bool { + ln := len(s) + if ln < 2 { + return false + } + if ln == 2 { + return s == "{}" + } + + // object + if s[0] == '{' { + return s[ln-1] == '}' && s[1] == '"' + } + return false +} + // `(?s:` enable match multi line var jsonMLComments = regexp.MustCompile(`(?s:/\*.*?\*/\s*)`) diff --git a/vendor/github.com/gookit/goutil/maputil/alias.go b/vendor/github.com/gookit/goutil/maputil/alias.go index 78618c456..b81095911 100644 --- a/vendor/github.com/gookit/goutil/maputil/alias.go +++ b/vendor/github.com/gookit/goutil/maputil/alias.go @@ -6,7 +6,7 @@ import "fmt" type Aliases map[string]string // AddAlias to the Aliases -func (as Aliases) AddAlias(real, alias string) { +func (as Aliases) AddAlias(alias, real string) { if rn, ok := as[alias]; ok { panic(fmt.Sprintf("The alias '%s' is already used by '%s'", alias, rn)) } @@ -16,14 +16,14 @@ func (as Aliases) AddAlias(real, alias string) { // AddAliases to the Aliases func (as Aliases) AddAliases(real string, aliases []string) { for _, a := range aliases { - as.AddAlias(real, a) + as.AddAlias(a, real) } } // AddAliasMap to the Aliases func (as Aliases) AddAliasMap(alias2real map[string]string) { for a, r := range alias2real { - as.AddAlias(r, a) + as.AddAlias(a, r) } } diff --git a/vendor/github.com/gookit/goutil/maputil/data.go b/vendor/github.com/gookit/goutil/maputil/data.go index 4049a8ba5..07008e78f 100644 --- a/vendor/github.com/gookit/goutil/maputil/data.go +++ b/vendor/github.com/gookit/goutil/maputil/data.go @@ -188,10 +188,7 @@ func (d Data) StrSplit(key, sep string) []string { // StringsByStr value get by key func (d Data) StringsByStr(key string) []string { - if val, ok := d.GetByPath(key); ok { - return strings.Split(strutil.QuietString(val), ",") - } - return nil + return d.StrSplit(key, ",") } // StrMap get map[string]string value diff --git a/vendor/github.com/gookit/goutil/maputil/format.go b/vendor/github.com/gookit/goutil/maputil/format.go index 96e5be3af..c7294737d 100644 --- a/vendor/github.com/gookit/goutil/maputil/format.go +++ b/vendor/github.com/gookit/goutil/maputil/format.go @@ -92,16 +92,16 @@ func (f *MapFormatter) doFormat() { } for i, key := range rv.MapKeys() { - kStr := strutil.QuietString(key.Interface()) + strK := strutil.SafeString(key.Interface()) if indentLn > 0 { buf.WriteString(f.Indent) } - buf.WriteString(kStr) + buf.WriteString(strK) buf.WriteByte(':') - vStr := strutil.QuietString(rv.MapIndex(key).Interface()) - buf.WriteString(vStr) + strV := strutil.SafeString(rv.MapIndex(key).Interface()) + buf.WriteString(strV) if i < ln-1 { buf.WriteByte(',') diff --git a/vendor/github.com/gookit/goutil/maputil/get.go b/vendor/github.com/gookit/goutil/maputil/get.go index c2236c47a..2f0f8916a 100644 --- a/vendor/github.com/gookit/goutil/maputil/get.go +++ b/vendor/github.com/gookit/goutil/maputil/get.go @@ -4,6 +4,8 @@ import ( "reflect" "strconv" "strings" + + "github.com/gookit/goutil/reflects" ) // some consts for separators @@ -24,8 +26,24 @@ func QuietGet(mp map[string]any, path string) (val any) { return } +// GetFromAny get value by key path from any(map,slice) data. eg "top" "top.sub" +func GetFromAny(path string, data any) (val any, ok bool) { + // empty data + if data == nil { + return nil, false + } + if len(path) == 0 { + return data, true + } + + return getByPathKeys(data, strings.Split(path, ".")) +} + // GetByPath get value by key path from a map(map[string]any). eg "top" "top.sub" func GetByPath(path string, mp map[string]any) (val any, ok bool) { + if len(path) == 0 { + return mp, true + } if val, ok := mp[path]; ok { return val, true } @@ -35,9 +53,8 @@ func GetByPath(path string, mp map[string]any) (val any, ok bool) { return nil, false } - // has sub key. eg. "top.sub" - keys := strings.Split(path, ".") - return GetByPathKeys(mp, keys) + // key is path. eg: "top.sub" + return GetByPathKeys(mp, strings.Split(path, ".")) } // GetByPathKeys get value by path keys from a map(map[string]any). eg "top" "top.sub" @@ -58,14 +75,19 @@ func GetByPathKeys(mp map[string]any, keys []string) (val any, ok bool) { // find top item data use top key var item any - topK := keys[0] if item, ok = mp[topK]; !ok { return } // find sub item data use sub key - for i, k := range keys[1:] { + return getByPathKeys(item, keys[1:]) +} + +func getByPathKeys(item any, keys []string) (val any, ok bool) { + kl := len(keys) + + for i, k := range keys { switch tData := item.(type) { case map[string]string: // is string map if item, ok = tData[k]; !ok { @@ -81,48 +103,77 @@ func GetByPathKeys(mp map[string]any, keys []string) (val any, ok bool) { } case []map[string]any: // is an any-map slice if k == Wildcard { - if kl == i+2 { + if kl == i+1 { // * is last key return tData, true } + // * is not last key, find sub item data sl := make([]any, 0, len(tData)) for _, v := range tData { - if val, ok = GetByPathKeys(v, keys[i+2:]); ok { + if val, ok = getByPathKeys(v, keys[i+1:]); ok { sl = append(sl, val) } } - return sl, true + + if len(sl) > 0 { + return sl, true + } + return nil, false } // k is index number idx, err := strconv.Atoi(k) - if err != nil { - return nil, false - } - - if idx >= len(tData) { + if err != nil || idx >= len(tData) { return nil, false } item = tData[idx] default: + if k == Wildcard && kl == i+1 { // * is last key + return tData, true + } + rv := reflect.ValueOf(tData) // check is slice if rv.Kind() == reflect.Slice { - i, err := strconv.Atoi(k) - if err != nil { - return nil, false - } - if i >= rv.Len() { + if k == Wildcard { + // * is not last key, find sub item data + sl := make([]any, 0, rv.Len()) + for si := 0; si < rv.Len(); si++ { + el := reflects.Indirect(rv.Index(si)) + if el.Kind() != reflect.Map { + return nil, false + } + + // el is map value. + if val, ok = getByPathKeys(el.Interface(), keys[i+1:]); ok { + sl = append(sl, val) + } + } + + if len(sl) > 0 { + return sl, true + } return nil, false } - item = rv.Index(i).Interface() + // check k is index number + ii, err := strconv.Atoi(k) + if err != nil || ii >= rv.Len() { + return nil, false + } + + item = rv.Index(ii).Interface() continue } // as error return nil, false } + + // next is last key and it is * + if kl == i+2 && keys[i+1] == Wildcard { + return item, true + } } return item, true diff --git a/vendor/github.com/gookit/goutil/maputil/smap.go b/vendor/github.com/gookit/goutil/maputil/smap.go index 47c9ad991..bcc74cc5e 100644 --- a/vendor/github.com/gookit/goutil/maputil/smap.go +++ b/vendor/github.com/gookit/goutil/maputil/smap.go @@ -29,6 +29,18 @@ func (m SMap) HasValue(val string) bool { return false } +// Load data to the map +func (m SMap) Load(data map[string]string) { + for k, v := range data { + m[k] = v + } +} + +// Set value to the data map +func (m SMap) Set(key string, val any) { + m[key] = strutil.MustString(val) +} + // Value get from the data map func (m SMap) Value(key string) (string, bool) { val, ok := m[key] diff --git a/vendor/github.com/gookit/goutil/mathutil/README.md b/vendor/github.com/gookit/goutil/mathutil/README.md index 71c9a7a39..4ebd14890 100644 --- a/vendor/github.com/gookit/goutil/mathutil/README.md +++ b/vendor/github.com/gookit/goutil/mathutil/README.md @@ -10,11 +10,91 @@ go get github.com/gookit/goutil/mathutil ## Go docs -- [Go docs](https://pkg.go.dev/github.com/gookit/goutil/mathutil) +- [Go Docs](https://pkg.go.dev/github.com/gookit/goutil) ## Usage +## Functions + +```go + +func CompFloat[T comdef.Float](first, second T, op string) (ok bool) +func CompInt[T comdef.Xint](first, second T, op string) (ok bool) +func CompInt64(first, second int64, op string) bool +func CompValue[T comdef.XintOrFloat](first, second T, op string) (ok bool) +func Compare(first, second any, op string) (ok bool) +func DataSize(size uint64) string +func ElapsedTime(startTime time.Time) string +func Float(in any) (float64, error) +func FloatOr(in any, defVal float64) float64 +func FloatOrDefault(in any, defVal float64) float64 +func FloatOrErr(in any) (float64, error) +func FloatOrPanic(in any) float64 +func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T +func GteOr[T comdef.XintOrFloat](val, min, defVal T) T +func HowLongAgo(sec int64) string +func InRange[T comdef.IntOrFloat](val, min, max T) bool +func InUintRange[T comdef.Uint](val, min, max T) bool +func Int(in any) (int, error) +func Int64(in any) (int64, error) +func Int64OrErr(in any) (int64, error) +func IntOr(in any, defVal int) int +func IntOrDefault(in any, defVal int) int +func IntOrErr(in any) (iVal int, err error) +func IntOrPanic(in any) int +func IsNumeric(c byte) bool +func LessOr[T comdef.XintOrFloat](val, max, devVal T) T +func LteOr[T comdef.XintOrFloat](val, max, devVal T) T +func Max[T comdef.XintOrFloat](x, y T) T +func MaxFloat(x, y float64) float64 +func MaxI64(x, y int64) int64 +func MaxInt(x, y int) int +func Min[T comdef.XintOrFloat](x, y T) T +func MustFloat(in any) float64 +func MustInt(in any) int +func MustInt64(in any) int64 +func MustString(val any) string +func MustUint(in any) uint64 +func OrElse[T comdef.XintOrFloat](val, defVal T) T +func OutRange[T comdef.IntOrFloat](val, min, max T) bool +func Percent(val, total int) float64 +func QuietFloat(in any) float64 +func QuietInt(in any) int +func QuietInt64(in any) int64 +func QuietString(val any) string +func QuietUint(in any) uint64 +func RandInt(min, max int) int +func RandIntWithSeed(min, max int, seed int64) int +func RandomInt(min, max int) int +func RandomIntWithSeed(min, max int, seed int64) int +func SafeFloat(in any) float64 +func SafeInt(in any) int +func SafeInt64(in any) int64 +func SafeUint(in any) uint64 +func StrInt(s string) int +func StrIntOr(s string, defVal int) int +func String(val any) string +func StringOrErr(val any) (string, error) +func StringOrPanic(val any) string +func SwapMax[T comdef.XintOrFloat](x, y T) (T, T) +func SwapMaxI64(x, y int64) (int64, int64) +func SwapMaxInt(x, y int) (int, int) +func SwapMin[T comdef.XintOrFloat](x, y T) (T, T) +func ToFloat(in any) (f64 float64, err error) +func ToFloatWithFunc(in any, usrFn func(any) (float64, error)) (f64 float64, err error) +func ToInt(in any) (iVal int, err error) +func ToInt64(in any) (i64 int64, err error) +func ToString(val any) (string, error) +func ToUint(in any) (u64 uint64, err error) +func ToUintWithFunc(in any, usrFn func(any) (uint64, error)) (u64 uint64, err error) +func TryToString(val any, defaultAsErr bool) (str string, err error) +func Uint(in any) (uint64, error) +func UintOrErr(in any) (uint64, error) +func ZeroOr[T comdef.XintOrFloat](val, defVal T) T + +``` + ## Testings ```shell diff --git a/vendor/github.com/gookit/goutil/mathutil/check.go b/vendor/github.com/gookit/goutil/mathutil/check.go index 055fc4df0..bd876031e 100644 --- a/vendor/github.com/gookit/goutil/mathutil/check.go +++ b/vendor/github.com/gookit/goutil/mathutil/check.go @@ -2,7 +2,12 @@ package mathutil import "github.com/gookit/goutil/comdef" -// Compare any intX,floatX value by given op. returns `srcVal op(=,!=,<,<=,>,>=) dstVal` +// IsNumeric returns true if the given character is a numeric, otherwise false. +func IsNumeric(c byte) bool { + return c >= '0' && c <= '9' +} + +// Compare any intX,floatX value by given op. returns `first op(=,!=,<,<=,>,>=) second` // // Usage: // @@ -10,70 +15,61 @@ import "github.com/gookit/goutil/comdef" // mathutil.Compare(2, 1.3, ">") // true // mathutil.Compare(2.2, 1.3, ">") // true // mathutil.Compare(2.1, 2, ">") // true -func Compare(srcVal, dstVal any, op string) (ok bool) { - if srcVal == nil || dstVal == nil { +func Compare(first, second any, op string) bool { + if first == nil || second == nil { return false } - // float - if srcFlt, ok := srcVal.(float64); ok { - if dstFlt, err := ToFloat(dstVal); err == nil { - return CompFloat(srcFlt, dstFlt, op) + switch fVal := first.(type) { + case float64: + if sVal, err := ToFloat(second); err == nil { + return CompFloat(fVal, sVal, op) } - return false - } - - if srcFlt, ok := srcVal.(float32); ok { - if dstFlt, err := ToFloat(dstVal); err == nil { - return CompFloat(float64(srcFlt), dstFlt, op) + case float32: + if sVal, err := ToFloat(second); err == nil { + return CompFloat(float64(fVal), sVal, op) + } + default: // as int64 + if int1, err := ToInt64(first); err == nil { + if int2, err := ToInt64(second); err == nil { + return CompInt64(int1, int2, op) + } } - return false } - // as int64 - srcInt, err := ToInt64(srcVal) - if err != nil { - return false - } - - dstInt, err := ToInt64(dstVal) - if err != nil { - return false - } - - return CompInt64(srcInt, dstInt, op) + return false } -// CompInt compare int,uint value. returns `srcVal op(=,!=,<,<=,>,>=) dstVal` -func CompInt[T comdef.Xint](srcVal, dstVal T, op string) (ok bool) { - return CompValue(srcVal, dstVal, op) +// CompInt compare all intX,uintX type value. returns `first op(=,!=,<,<=,>,>=) second` +func CompInt[T comdef.Xint](first, second T, op string) (ok bool) { + return CompValue(first, second, op) } -// CompInt64 compare int64 value. returns `srcVal op(=,!=,<,<=,>,>=) dstVal` -func CompInt64(srcVal, dstVal int64, op string) bool { - return CompValue(srcVal, dstVal, op) +// CompInt64 compare int64 value. returns `first op(=,!=,<,<=,>,>=) second` +func CompInt64(first, second int64, op string) bool { + return CompValue(first, second, op) } -// CompFloat compare float64,float32 value. returns `srcVal op(=,!=,<,<=,>,>=) dstVal` -func CompFloat[T comdef.Float](srcVal, dstVal T, op string) (ok bool) { - return CompValue(srcVal, dstVal, op) +// CompFloat compare float64,float32 value. returns `first op(=,!=,<,<=,>,>=) second` +func CompFloat[T comdef.Float](first, second T, op string) (ok bool) { + return CompValue(first, second, op) } -// CompValue compare intX,uintX,floatX value. returns `srcVal op(=,!=,<,<=,>,>=) dstVal` -func CompValue[T comdef.XintOrFloat](srcVal, dstVal T, op string) (ok bool) { +// CompValue compare intX,uintX,floatX value. returns `first op(=,!=,<,<=,>,>=) second` +func CompValue[T comdef.XintOrFloat](first, second T, op string) (ok bool) { switch op { case "<", "lt": - ok = srcVal < dstVal + ok = first < second case "<=", "lte": - ok = srcVal <= dstVal + ok = first <= second case ">", "gt": - ok = srcVal > dstVal + ok = first > second case ">=", "gte": - ok = srcVal >= dstVal + ok = first >= second case "=", "eq": - ok = srcVal == dstVal + ok = first == second case "!=", "ne", "neq": - ok = srcVal != dstVal + ok = first != second } return } diff --git a/vendor/github.com/gookit/goutil/mathutil/compare.go b/vendor/github.com/gookit/goutil/mathutil/compare.go new file mode 100644 index 000000000..f18e28a5c --- /dev/null +++ b/vendor/github.com/gookit/goutil/mathutil/compare.go @@ -0,0 +1,76 @@ +package mathutil + +import ( + "math" + + "github.com/gookit/goutil/comdef" +) + +// Min compare two value and return max value +func Min[T comdef.XintOrFloat](x, y T) T { + if x < y { + return x + } + return y +} + +// Max compare two value and return max value +func Max[T comdef.XintOrFloat](x, y T) T { + if x > y { + return x + } + return y +} + +// SwapMin compare and always return [min, max] value +func SwapMin[T comdef.XintOrFloat](x, y T) (T, T) { + if x < y { + return x, y + } + return y, x +} + +// SwapMax compare and always return [max, min] value +func SwapMax[T comdef.XintOrFloat](x, y T) (T, T) { + if x > y { + return x, y + } + return y, x +} + +// MaxInt compare and return max value +func MaxInt(x, y int) int { + if x > y { + return x + } + return y +} + +// SwapMaxInt compare and return max, min value +func SwapMaxInt(x, y int) (int, int) { + if x > y { + return x, y + } + return y, x +} + +// MaxI64 compare and return max value +func MaxI64(x, y int64) int64 { + if x > y { + return x + } + return y +} + +// SwapMaxI64 compare and return max, min value +func SwapMaxI64(x, y int64) (int64, int64) { + if x > y { + return x, y + } + return y, x +} + +// MaxFloat compare and return max value +func MaxFloat(x, y float64) float64 { + return math.Max(x, y) +} diff --git a/vendor/github.com/gookit/goutil/mathutil/convert.go b/vendor/github.com/gookit/goutil/mathutil/convert.go index 4034e3918..1d405714a 100644 --- a/vendor/github.com/gookit/goutil/mathutil/convert.go +++ b/vendor/github.com/gookit/goutil/mathutil/convert.go @@ -1,8 +1,8 @@ package mathutil import ( - "encoding/json" "fmt" + "math" "strconv" "strings" "time" @@ -10,6 +10,18 @@ import ( "github.com/gookit/goutil/comdef" ) +// ToIntFunc convert value to int +type ToIntFunc func(any) (int, error) + +// ToInt64Func convert value to int64 +type ToInt64Func func(any) (int64, error) + +// ToUintFunc convert value to uint +type ToUintFunc func(any) (uint64, error) + +// ToFloatFunc convert value to float +type ToFloatFunc func(any) (float64, error) + /************************************************************* * convert value to int *************************************************************/ @@ -19,20 +31,19 @@ func Int(in any) (int, error) { return ToInt(in) } -// QuietInt convert value to int, will ignore error -func QuietInt(in any) int { +// SafeInt convert value to int, will ignore error +func SafeInt(in any) int { val, _ := ToInt(in) return val } +// QuietInt convert value to int, will ignore error +func QuietInt(in any) int { + return SafeInt(in) +} + // MustInt convert value to int, will panic on error func MustInt(in any) int { - val, _ := ToInt(in) - return val -} - -// IntOrPanic convert value to int, will panic on error -func IntOrPanic(in any) int { val, err := ToInt(in) if err != nil { panic(err) @@ -40,16 +51,38 @@ func IntOrPanic(in any) int { return val } +// IntOrPanic convert value to int, will panic on error +func IntOrPanic(in any) int { + return MustInt(in) +} + +// IntOrDefault convert value to int, return defaultVal on failed +func IntOrDefault(in any, defVal int) int { + return IntOr(in, defVal) +} + +// IntOr convert value to int, return defaultVal on failed +func IntOr(in any, defVal int) int { + val, err := ToIntWithFunc(in, nil) + if err != nil { + return defVal + } + return val +} + // IntOrErr convert value to int, return error on failed func IntOrErr(in any) (iVal int, err error) { - return ToInt(in) + return ToIntWithFunc(in, nil) } // ToInt convert value to int, return error on failed func ToInt(in any) (iVal int, err error) { + return ToIntWithFunc(in, nil) +} + +// ToIntWithFunc convert value to int, will call usrFn on value type not supported. +func ToIntWithFunc(in any, usrFn ToIntFunc) (iVal int, err error) { switch tVal := in.(type) { - case nil: - iVal = 0 case int: iVal = tVal case int8: @@ -59,31 +92,60 @@ func ToInt(in any) (iVal int, err error) { case int32: iVal = int(tVal) case int64: - iVal = int(tVal) + if tVal > math.MaxInt32 { + err = fmt.Errorf("value overflow int32. input: %v", tVal) + } else { + iVal = int(tVal) + } case uint: - iVal = int(tVal) + if tVal > math.MaxInt32 { + err = fmt.Errorf("value overflow int32. input: %v", tVal) + } else { + iVal = int(tVal) + } case uint8: iVal = int(tVal) case uint16: iVal = int(tVal) case uint32: - iVal = int(tVal) + if tVal > math.MaxInt32 { + err = fmt.Errorf("value overflow int32. input: %v", tVal) + } else { + iVal = int(tVal) + } case uint64: - iVal = int(tVal) + if tVal > math.MaxInt32 { + err = fmt.Errorf("value overflow int32. input: %v", tVal) + } else { + iVal = int(tVal) + } case float32: iVal = int(tVal) case float64: iVal = int(tVal) case time.Duration: - iVal = int(tVal) + if tVal > math.MaxInt32 { + err = fmt.Errorf("value overflow int32. input: %v", tVal) + } else { + iVal = int(tVal) + } case string: iVal, err = strconv.Atoi(strings.TrimSpace(tVal)) - case json.Number: + case interface{ Int64() (int64, error) }: // eg: json.Number var i64 int64 - i64, err = tVal.Int64() - iVal = int(i64) + if i64, err = tVal.Int64(); err == nil { + if i64 > math.MaxInt32 { + err = fmt.Errorf("value overflow int32. input: %v", tVal) + } else { + iVal = int(i64) + } + } default: - err = comdef.ErrConvType + if usrFn != nil { + return usrFn(in) + } else { + err = comdef.ErrConvType + } } return } @@ -94,37 +156,71 @@ func StrInt(s string) int { return iVal } +// StrIntOr convert string to int, return default val on failed +func StrIntOr(s string, defVal int) int { + iVal, err := strconv.Atoi(strings.TrimSpace(s)) + if err != nil { + return defVal + } + return iVal +} + /************************************************************* * convert value to uint *************************************************************/ -// Uint convert string to uint, return error on failed +// Uint convert any to uint, return error on failed func Uint(in any) (uint64, error) { return ToUint(in) } -// QuietUint convert string to uint, will ignore error -func QuietUint(in any) uint64 { +// SafeUint convert any to uint, will ignore error +func SafeUint(in any) uint64 { val, _ := ToUint(in) return val } -// MustUint convert string to uint, will panic on error +// QuietUint convert any to uint, will ignore error +func QuietUint(in any) uint64 { + return SafeUint(in) +} + +// MustUint convert any to uint, will panic on error func MustUint(in any) uint64 { - val, _ := ToUint(in) + val, err := ToUintWithFunc(in, nil) + if err != nil { + panic(err) + } + return val +} + +// UintOrDefault convert any to uint, return default val on failed +func UintOrDefault(in any, defVal uint64) uint64 { + return UintOr(in, defVal) +} + +// UintOr convert any to uint, return default val on failed +func UintOr(in any, defVal uint64) uint64 { + val, err := ToUintWithFunc(in, nil) + if err != nil { + return defVal + } return val } // UintOrErr convert value to uint, return error on failed func UintOrErr(in any) (uint64, error) { - return ToUint(in) + return ToUintWithFunc(in, nil) } // ToUint convert value to uint, return error on failed func ToUint(in any) (u64 uint64, err error) { + return ToUintWithFunc(in, nil) +} + +// ToUintWithFunc convert value to uint, will call usrFn on value type not supported. +func ToUintWithFunc(in any, usrFn ToUintFunc) (u64 uint64, err error) { switch tVal := in.(type) { - case nil: - u64 = 0 case int: u64 = uint64(tVal) case int8: @@ -151,14 +247,18 @@ func ToUint(in any) (u64 uint64, err error) { u64 = uint64(tVal) case time.Duration: u64 = uint64(tVal) - case json.Number: + case interface{ Int64() (int64, error) }: // eg: json.Number var i64 int64 i64, err = tVal.Int64() u64 = uint64(i64) case string: u64, err = strconv.ParseUint(strings.TrimSpace(tVal), 10, 0) default: - err = comdef.ErrConvType + if usrFn != nil { + u64, err = usrFn(in) + } else { + err = comdef.ErrConvType + } } return } @@ -167,41 +267,58 @@ func ToUint(in any) (u64 uint64, err error) { * convert value to int64 *************************************************************/ -// Int64 convert string to int64, return error on failed +// Int64 convert value to int64, return error on failed func Int64(in any) (int64, error) { return ToInt64(in) } // SafeInt64 convert value to int64, will ignore error func SafeInt64(in any) int64 { - i64, _ := ToInt64(in) + i64, _ := ToInt64WithFunc(in, nil) return i64 } // QuietInt64 convert value to int64, will ignore error func QuietInt64(in any) int64 { - i64, _ := ToInt64(in) - return i64 + return SafeInt64(in) } // MustInt64 convert value to int64, will panic on error func MustInt64(in any) int64 { - i64, _ := ToInt64(in) + i64, err := ToInt64WithFunc(in, nil) + if err != nil { + panic(err) + } return i64 } -// TODO StrictInt64,AsInt64 strict convert to int64 +// Int64OrDefault convert value to int64, return default val on failed +func Int64OrDefault(in any, defVal int64) int64 { + return Int64Or(in, defVal) +} -// Int64OrErr convert string to int64, return error on failed +// Int64Or convert value to int64, return default val on failed +func Int64Or(in any, defVal int64) int64 { + i64, err := ToInt64WithFunc(in, nil) + if err != nil { + return defVal + } + return i64 +} + +// Int64OrErr convert value to int64, return error on failed func Int64OrErr(in any) (int64, error) { return ToInt64(in) } -// ToInt64 convert string to int64, return error on failed +// ToInt64 convert value to int64, return error on failed func ToInt64(in any) (i64 int64, err error) { + return ToInt64WithFunc(in, nil) +} + +// ToInt64WithFunc convert value to int64, will call usrFn on value type not supported. +func ToInt64WithFunc(in any, usrFn ToInt64Func) (i64 int64, err error) { switch tVal := in.(type) { - case nil: - i64 = 0 case string: i64, err = strconv.ParseInt(strings.TrimSpace(tVal), 10, 0) case int: @@ -230,10 +347,14 @@ func ToInt64(in any) (i64 int64, err error) { i64 = int64(tVal) case time.Duration: i64 = int64(tVal) - case json.Number: + case interface{ Int64() (int64, error) }: // eg: json.Number i64, err = tVal.Int64() default: - err = comdef.ErrConvType + if usrFn != nil { + i64, err = usrFn(in) + } else { + err = comdef.ErrConvType + } } return } @@ -242,42 +363,63 @@ func ToInt64(in any) (i64 int64, err error) { * convert value to float *************************************************************/ -// QuietFloat convert value to float64, will ignore error +// QuietFloat convert value to float64, will ignore error. alias of SafeFloat func QuietFloat(in any) float64 { - val, _ := ToFloat(in) + return SafeFloat(in) +} + +// SafeFloat convert value to float64, will ignore error +func SafeFloat(in any) float64 { + val, _ := ToFloatWithFunc(in, nil) return val } // FloatOrPanic convert value to float64, will panic on error func FloatOrPanic(in any) float64 { - val, err := ToFloat(in) + return MustFloat(in) +} + +// MustFloat convert value to float64, will panic on error +func MustFloat(in any) float64 { + val, err := ToFloatWithFunc(in, nil) if err != nil { panic(err) } return val } -// MustFloat convert value to float64 TODO will panic on error -func MustFloat(in any) float64 { - val, _ := ToFloat(in) +// FloatOrDefault convert value to float64, will return default value on error +func FloatOrDefault(in any, defVal float64) float64 { + return FloatOr(in, defVal) +} + +// FloatOr convert value to float64, will return default value on error +func FloatOr(in any, defVal float64) float64 { + val, err := ToFloatWithFunc(in, nil) + if err != nil { + return defVal + } return val } // Float convert value to float64, return error on failed func Float(in any) (float64, error) { - return ToFloat(in) + return ToFloatWithFunc(in, nil) } // FloatOrErr convert value to float64, return error on failed func FloatOrErr(in any) (float64, error) { - return ToFloat(in) + return ToFloatWithFunc(in, nil) } // ToFloat convert value to float64, return error on failed func ToFloat(in any) (f64 float64, err error) { + return ToFloatWithFunc(in, nil) +} + +// ToFloatWithFunc convert value to float64, will call usrFn if value type not supported. +func ToFloatWithFunc(in any, usrFn ToFloatFunc) (f64 float64, err error) { switch tVal := in.(type) { - case nil: - f64 = 0 case string: f64, err = strconv.ParseFloat(strings.TrimSpace(tVal), 64) case int: @@ -306,10 +448,14 @@ func ToFloat(in any) (f64 float64, err error) { f64 = tVal case time.Duration: f64 = float64(tVal) - case json.Number: + case interface{ Float64() (float64, error) }: // eg: json.Number f64, err = tVal.Float64() default: - err = comdef.ErrConvType + if usrFn != nil { + f64, err = usrFn(in) + } else { + err = comdef.ErrConvType + } } return } @@ -318,34 +464,45 @@ func ToFloat(in any) (f64 float64, err error) { * convert intX/floatX to string *************************************************************/ -// StringOrPanic convert intX/floatX value to string, will panic on error -func StringOrPanic(val any) string { - str, err := TryToString(val, true) +// MustString convert intX/floatX value to string, will panic on error +func MustString(val any) string { + str, err := ToStringWithFunc(val, nil) if err != nil { panic(err) } return str } -// MustString convert intX/floatX value to string, will panic on error -func MustString(val any) string { - return StringOrPanic(val) +// StringOrPanic convert intX/floatX value to string, will panic on error +func StringOrPanic(val any) string { return MustString(val) } + +// StringOrDefault convert intX/floatX value to string, will return default value on error +func StringOrDefault(val any, defVal string) string { + return StringOr(val, defVal) +} + +// StringOr convert intX/floatX value to string, will return default value on error +func StringOr(val any, defVal string) string { + str, err := ToStringWithFunc(val, nil) + if err != nil { + return defVal + } + return str } // ToString convert intX/floatX value to string, return error on failed func ToString(val any) (string, error) { - return TryToString(val, true) + return ToStringWithFunc(val, nil) } // StringOrErr convert intX/floatX value to string, return error on failed func StringOrErr(val any) (string, error) { - return TryToString(val, true) + return ToStringWithFunc(val, nil) } // QuietString convert intX/floatX value to string, other type convert by fmt.Sprint func QuietString(val any) string { - str, _ := TryToString(val, false) - return str + return SafeString(val) } // String convert intX/floatX value to string, other type convert by fmt.Sprint @@ -354,14 +511,33 @@ func String(val any) string { return str } +// SafeString convert intX/floatX value to string, other type convert by fmt.Sprint +func SafeString(val any) string { + str, _ := TryToString(val, false) + return str +} + // TryToString try convert intX/floatX value to string // // if defaultAsErr is False, will use fmt.Sprint convert other type func TryToString(val any, defaultAsErr bool) (str string, err error) { - if val == nil { - return + var usrFn comdef.ToStringFunc + if !defaultAsErr { + usrFn = func(v any) (string, error) { + if val == nil { + return "", nil + } + return fmt.Sprint(v), nil + } } + return ToStringWithFunc(val, usrFn) +} + +// ToStringWithFunc try convert intX/floatX value to string, will call usrFn if value type not supported. +// +// if defaultAsErr is False, will use fmt.Sprint convert other type +func ToStringWithFunc(val any, usrFn comdef.ToStringFunc) (str string, err error) { switch value := val.(type) { case int: str = strconv.Itoa(value) @@ -389,14 +565,31 @@ func TryToString(val any, defaultAsErr bool) (str string, err error) { str = strconv.FormatFloat(value, 'f', -1, 64) case time.Duration: str = strconv.FormatInt(int64(value), 10) + case string: + str = value case fmt.Stringer: str = value.String() default: - if defaultAsErr { - err = comdef.ErrConvType + if usrFn != nil { + str, err = usrFn(val) } else { - str = fmt.Sprint(value) + err = comdef.ErrConvType } } return } + +// Percent returns a values percent of the total +func Percent(val, total int) float64 { + if total == 0 { + return float64(0) + } + return (float64(val) / float64(total)) * 100 +} + +// ElapsedTime calc elapsed time 计算运行时间消耗 单位 ms(毫秒) +// +// Deprecated: use timex.ElapsedTime() +func ElapsedTime(startTime time.Time) string { + return fmt.Sprintf("%.3f", time.Since(startTime).Seconds()*1000) +} diff --git a/vendor/github.com/gookit/goutil/basefn/extfunc.go b/vendor/github.com/gookit/goutil/mathutil/format.go similarity index 86% rename from vendor/github.com/gookit/goutil/basefn/extfunc.go rename to vendor/github.com/gookit/goutil/mathutil/format.go index 15be452cf..deb29fd2a 100644 --- a/vendor/github.com/gookit/goutil/basefn/extfunc.go +++ b/vendor/github.com/gookit/goutil/mathutil/format.go @@ -1,8 +1,6 @@ -package basefn +package mathutil -import ( - "fmt" -) +import "fmt" // DataSize format bytes number friendly. eg: 1024 => 1KB, 1024*1024 => 1MB // @@ -33,14 +31,16 @@ var timeFormats = [][]int{ {3600}, {7200, 3600}, {86400}, - {172800, 86400}, + {172800, 86400}, // second elem is unit. + {2592000}, + {2592000 * 2, 2592000}, } var timeMessages = []string{ - "< 1 sec", "1 sec", "secs", "1 min", "mins", "1 hr", "hrs", "1 day", "days", + "< 1 sec", "1 sec", "secs", "1 min", "mins", "1 hr", "hrs", "1 day", "days", "1 month", "months", } -// HowLongAgo format a seconds, get how lang ago +// HowLongAgo format a seconds, get how lang ago. eg: 1 day, 1 week func HowLongAgo(sec int64) string { intVal := int(sec) length := len(timeFormats) @@ -63,8 +63,6 @@ func HowLongAgo(sec int64) string { if len(item) == 1 { return timeMessages[i] } - - // len is 2 return fmt.Sprintf("%d %s", intVal/item[1], timeMessages[i]) } } diff --git a/vendor/github.com/gookit/goutil/mathutil/mathutil.go b/vendor/github.com/gookit/goutil/mathutil/mathutil.go index 52a2e145d..1b47f32a9 100644 --- a/vendor/github.com/gookit/goutil/mathutil/mathutil.go +++ b/vendor/github.com/gookit/goutil/mathutil/mathutil.go @@ -2,84 +2,72 @@ package mathutil import ( - "math" - "github.com/gookit/goutil/comdef" ) -// Min compare two value and return max value -func Min[T comdef.XintOrFloat](x, y T) T { - if x < y { - return x - } - return y +// OrElse return default value on val is zero, else return val +func OrElse[T comdef.XintOrFloat](val, defVal T) T { + return ZeroOr(val, defVal) } -// Max compare two value and return max value -func Max[T comdef.XintOrFloat](x, y T) T { - if x > y { - return x +// ZeroOr return default value on val is zero, else return val +func ZeroOr[T comdef.XintOrFloat](val, defVal T) T { + if val != 0 { + return val } - return y + return defVal } -// SwapMin compare and always return [min, max] value -func SwapMin[T comdef.XintOrFloat](x, y T) (T, T) { - if x < y { - return x, y +// LessOr return val on val < max, else return default value. +// +// Example: +// +// LessOr(11, 10, 1) // 1 +// LessOr(2, 10, 1) // 2 +// LessOr(10, 10, 1) // 1 +func LessOr[T comdef.XintOrFloat](val, max, devVal T) T { + if val < max { + return val } - return y, x + return devVal } -// SwapMax compare and always return [max, min] value -func SwapMax[T comdef.XintOrFloat](x, y T) (T, T) { - if x > y { - return x, y +// LteOr return val on val <= max, else return default value. +// +// Example: +// +// LteOr(11, 10, 1) // 11 +// LteOr(2, 10, 1) // 2 +// LteOr(10, 10, 1) // 10 +func LteOr[T comdef.XintOrFloat](val, max, devVal T) T { + if val <= max { + return val } - return y, x + return devVal } -// MaxInt compare and return max value -func MaxInt(x, y int) int { - if x > y { - return x +// GreaterOr return val on val > max, else return default value. +// +// Example: +// +// GreaterOr(23, 0, 2) // 23 +// GreaterOr(0, 0, 2) // 2 +func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T { + if val > min { + return val } - return y + return defVal } -// SwapMaxInt compare and return max, min value -func SwapMaxInt(x, y int) (int, int) { - if x > y { - return x, y +// GteOr return val on val >= max, else return default value. +// +// Example: +// +// GteOr(23, 0, 2) // 23 +// GteOr(0, 0, 2) // 0 +func GteOr[T comdef.XintOrFloat](val, min, defVal T) T { + if val >= min { + return val } - return y, x -} - -// MaxI64 compare and return max value -func MaxI64(x, y int64) int64 { - if x > y { - return x - } - return y -} - -// SwapMaxI64 compare and return max, min value -func SwapMaxI64(x, y int64) (int64, int64) { - if x > y { - return x, y - } - return y, x -} - -// MaxFloat compare and return max value -func MaxFloat(x, y float64) float64 { - return math.Max(x, y) -} - -// OrElse return s OR nv(new-value) on s is empty -func OrElse[T comdef.XintOrFloat](in, nv T) T { - if in != 0 { - return in - } - return nv + return defVal } diff --git a/vendor/github.com/gookit/goutil/mathutil/number.go b/vendor/github.com/gookit/goutil/mathutil/number.go deleted file mode 100644 index 5b1359463..000000000 --- a/vendor/github.com/gookit/goutil/mathutil/number.go +++ /dev/null @@ -1,37 +0,0 @@ -package mathutil - -import ( - "fmt" - "time" - - "github.com/gookit/goutil/basefn" -) - -// IsNumeric returns true if the given character is a numeric, otherwise false. -func IsNumeric(c byte) bool { - return c >= '0' && c <= '9' -} - -// Percent returns a values percent of the total -func Percent(val, total int) float64 { - if total == 0 { - return float64(0) - } - return (float64(val) / float64(total)) * 100 -} - -// ElapsedTime calc elapsed time 计算运行时间消耗 单位 ms(毫秒) -func ElapsedTime(startTime time.Time) string { - return fmt.Sprintf("%.3f", time.Since(startTime).Seconds()*1000) -} - -// DataSize format value to data size string. eg: 1024 => 1KB, 1024*1024 => 1MB -// alias format.DataSize() -func DataSize(size uint64) string { - return basefn.DataSize(size) -} - -// HowLongAgo calc time. alias format.HowLongAgo() -func HowLongAgo(sec int64) string { - return basefn.HowLongAgo(sec) -} diff --git a/vendor/github.com/gookit/goutil/mathutil/random.go b/vendor/github.com/gookit/goutil/mathutil/random.go index 477b56efd..d6713a209 100644 --- a/vendor/github.com/gookit/goutil/mathutil/random.go +++ b/vendor/github.com/gookit/goutil/mathutil/random.go @@ -13,8 +13,8 @@ import ( // RandomInt(100, 999) // RandomInt(1000, 9999) func RandomInt(min, max int) int { - rand.Seed(time.Now().UnixNano()) - return min + rand.Intn(max-min) + rr := rand.New(rand.NewSource(time.Now().UnixNano())) + return min + rr.Intn(max-min) } // RandInt alias of RandomInt() @@ -32,6 +32,6 @@ func RandIntWithSeed(min, max int, seed int64) int { // seed := time.Now().UnixNano() // RandomIntWithSeed(1000, 9999, seed) func RandomIntWithSeed(min, max int, seed int64) int { - rand.Seed(seed) - return min + rand.Intn(max-min) + rr := rand.New(rand.NewSource(seed)) + return min + rr.Intn(max-min) } diff --git a/vendor/github.com/gookit/goutil/reflects/check.go b/vendor/github.com/gookit/goutil/reflects/check.go index 7ca257c77..062ce6bc5 100644 --- a/vendor/github.com/gookit/goutil/reflects/check.go +++ b/vendor/github.com/gookit/goutil/reflects/check.go @@ -27,11 +27,16 @@ func IsSimpleKind(k reflect.Kind) bool { return k > reflect.Invalid && k <= reflect.Float64 } -// IsAnyInt check is intX or uintX type +// IsAnyInt check is intX or uintX type. alias of the IsIntLike() func IsAnyInt(k reflect.Kind) bool { return k >= reflect.Int && k <= reflect.Uintptr } +// IsIntLike reports whether the type is int-like(intX, uintX). +func IsIntLike(k reflect.Kind) bool { + return k >= reflect.Int && k <= reflect.Uintptr +} + // IsIntx check is intX type func IsIntx(k reflect.Kind) bool { return k >= reflect.Int && k <= reflect.Int64 @@ -52,6 +57,17 @@ func IsNil(v reflect.Value) bool { } } +// CanBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero. +func CanBeNil(typ reflect.Type) bool { + switch typ.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice: + return true + case reflect.Struct: + return typ == reflectValueType + } + return false +} + // IsFunc value func IsFunc(val any) bool { if val == nil { @@ -84,6 +100,9 @@ func IsEqual(src, dst any) bool { return bytes.Equal(bs1, bs2) } +// IsZero reflect value check, alias of the IsEmpty() +var IsZero = IsEmpty + // IsEmpty reflect value check func IsEmpty(v reflect.Value) bool { switch v.Kind() { @@ -108,11 +127,17 @@ func IsEmpty(v reflect.Value) bool { return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) } -// IsEmptyValue reflect value check. -// Difference the IsEmpty(), if value is ptr, will check real elem. +// IsEmptyValue reflect value check, alias of the IsEmptyReal() +var IsEmptyValue = IsEmptyReal + +// IsEmptyReal reflect value check. +// +// Note: +// +// Difference the IsEmpty(), if value is ptr or interface, will check real elem. // // From src/pkg/encoding/json/encode.go. -func IsEmptyValue(v reflect.Value) bool { +func IsEmptyReal(v reflect.Value) bool { switch v.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: return v.Len() == 0 @@ -128,11 +153,12 @@ func IsEmptyValue(v reflect.Value) bool { if v.IsNil() { return true } - return IsEmptyValue(v.Elem()) + return IsEmptyReal(v.Elem()) case reflect.Func: return v.IsNil() case reflect.Invalid: return true } - return false + + return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) } diff --git a/vendor/github.com/gookit/goutil/reflects/conv.go b/vendor/github.com/gookit/goutil/reflects/conv.go index 1dfa303a5..f5376ec41 100644 --- a/vendor/github.com/gookit/goutil/reflects/conv.go +++ b/vendor/github.com/gookit/goutil/reflects/conv.go @@ -2,6 +2,7 @@ package reflects import ( "fmt" + "math" "reflect" "strconv" @@ -12,13 +13,19 @@ import ( ) // BaseTypeVal convert custom type or intX,uintX,floatX to generic base type. +func BaseTypeVal(v reflect.Value) (value any, err error) { + return ToBaseVal(v) +} + +// ToBaseVal convert custom type or intX,uintX,floatX to generic base type. // -// intX/unitX => int64 +// intX => int64 +// unitX => uint64 // floatX => float64 // string => string // // returns int64,string,float or error -func BaseTypeVal(v reflect.Value) (value any, err error) { +func ToBaseVal(v reflect.Value) (value any, err error) { v = reflect.Indirect(v) switch v.Kind() { @@ -27,7 +34,7 @@ func BaseTypeVal(v reflect.Value) (value any, err error) { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: value = v.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - value = int64(v.Uint()) // always return int64 + value = v.Uint() // always return int64 case reflect.Float32, reflect.Float64: value = v.Float() default: @@ -36,14 +43,23 @@ func BaseTypeVal(v reflect.Value) (value any, err error) { return } +// ConvToType convert and create reflect.Value by give reflect.Type +func ConvToType(val any, typ reflect.Type) (rv reflect.Value, err error) { + return ValueByType(val, typ) +} + // ValueByType create reflect.Value by give reflect.Type func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error) { // handle kind: string, bool, intX, uintX, floatX if typ.Kind() == reflect.String || typ.Kind() <= reflect.Float64 { - return ValueByKind(val, typ.Kind()) + return ConvToKind(val, typ.Kind()) } - newRv := reflect.ValueOf(val) + var ok bool + var newRv reflect.Value + if newRv, ok = val.(reflect.Value); !ok { + newRv = reflect.ValueOf(val) + } // try auto convert slice type if IsArrayOrSlice(newRv.Kind()) && IsArrayOrSlice(typ.Kind()) { @@ -59,72 +75,116 @@ func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error) { return } -// ValueByKind create reflect.Value by give reflect.Kind +// ValueByKind convert and create reflect.Value by give reflect.Kind +func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) { + return ConvToKind(val, kind) +} + +// ConvToKind convert and create reflect.Value by give reflect.Kind // // TIPs: // // Only support kind: string, bool, intX, uintX, floatX -func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) { +func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error) { + if rv, ok := val.(reflect.Value); ok { + val = rv.Interface() + } + switch kind { case reflect.Int: - if dstV, err1 := mathutil.ToInt(val); err1 == nil { + var dstV int + if dstV, err = mathutil.ToInt(val); err == nil { rv = reflect.ValueOf(dstV) } case reflect.Int8: - if dstV, err1 := mathutil.ToInt(val); err1 == nil { + var dstV int + if dstV, err = mathutil.ToInt(val); err == nil { + if dstV > math.MaxInt8 { + return rv, fmt.Errorf("value overflow int8. val: %v", val) + } rv = reflect.ValueOf(int8(dstV)) } case reflect.Int16: - if dstV, err1 := mathutil.ToInt(val); err1 == nil { + var dstV int + if dstV, err = mathutil.ToInt(val); err == nil { + if dstV > math.MaxInt16 { + return rv, fmt.Errorf("value overflow int16. val: %v", val) + } rv = reflect.ValueOf(int16(dstV)) } case reflect.Int32: - if dstV, err1 := mathutil.ToInt(val); err1 == nil { + var dstV int + if dstV, err = mathutil.ToInt(val); err == nil { + if dstV > math.MaxInt32 { + return rv, fmt.Errorf("value overflow int32. val: %v", val) + } rv = reflect.ValueOf(int32(dstV)) } case reflect.Int64: - if dstV, err1 := mathutil.ToInt64(val); err1 == nil { + var dstV int64 + if dstV, err = mathutil.ToInt64(val); err == nil { rv = reflect.ValueOf(dstV) } case reflect.Uint: - if dstV, err1 := mathutil.ToUint(val); err1 == nil { + var dstV uint64 + if dstV, err = mathutil.ToUint(val); err == nil { rv = reflect.ValueOf(uint(dstV)) } case reflect.Uint8: - if dstV, err1 := mathutil.ToUint(val); err1 == nil { + var dstV uint64 + if dstV, err = mathutil.ToUint(val); err == nil { + if dstV > math.MaxUint8 { + return rv, fmt.Errorf("value overflow uint8. val: %v", val) + } rv = reflect.ValueOf(uint8(dstV)) } case reflect.Uint16: - if dstV, err1 := mathutil.ToUint(val); err1 == nil { + var dstV uint64 + if dstV, err = mathutil.ToUint(val); err == nil { + if dstV > math.MaxUint16 { + return rv, fmt.Errorf("value overflow uint16. val: %v", val) + } rv = reflect.ValueOf(uint16(dstV)) } case reflect.Uint32: - if dstV, err1 := mathutil.ToUint(val); err1 == nil { + var dstV uint64 + if dstV, err = mathutil.ToUint(val); err == nil { + if dstV > math.MaxUint32 { + return rv, fmt.Errorf("value overflow uint32. val: %v", val) + } rv = reflect.ValueOf(uint32(dstV)) } case reflect.Uint64: - if dstV, err1 := mathutil.ToUint(val); err1 == nil { + var dstV uint64 + if dstV, err = mathutil.ToUint(val); err == nil { rv = reflect.ValueOf(dstV) } case reflect.Float32: - if dstV, err1 := mathutil.ToFloat(val); err1 == nil { + var dstV float64 + if dstV, err = mathutil.ToFloat(val); err == nil { + if dstV > math.MaxFloat32 { + return rv, fmt.Errorf("value overflow float32. val: %v", val) + } rv = reflect.ValueOf(float32(dstV)) } case reflect.Float64: - if dstV, err1 := mathutil.ToFloat(val); err1 == nil { + var dstV float64 + if dstV, err = mathutil.ToFloat(val); err == nil { rv = reflect.ValueOf(dstV) } case reflect.String: if dstV, err1 := strutil.ToString(val); err1 == nil { rv = reflect.ValueOf(dstV) + } else { + err = err1 } case reflect.Bool: - if bl, err := comfunc.ToBool(val); err == nil { + if bl, err1 := comfunc.ToBool(val); err1 == nil { rv = reflect.ValueOf(bl) + } else { + err = err1 } - } - - if !rv.IsValid() { + default: err = comdef.ErrConvType } return diff --git a/vendor/github.com/gookit/goutil/reflects/func.go b/vendor/github.com/gookit/goutil/reflects/func.go new file mode 100644 index 000000000..408d21f0e --- /dev/null +++ b/vendor/github.com/gookit/goutil/reflects/func.go @@ -0,0 +1,317 @@ +package reflects + +import ( + "errors" + "fmt" + "reflect" + + "github.com/gookit/goutil/basefn" +) + +// FuncX wrap a go func. represent a function +type FuncX struct { + CallOpt + // Name of func. eg: "MyFunc" + Name string + // rv is the `reflect.Value` of func + rv reflect.Value + rt reflect.Type +} + +// NewFunc instance. param fn support func and reflect.Value +func NewFunc(fn any) *FuncX { + var ok bool + var rv reflect.Value + if rv, ok = fn.(reflect.Value); !ok { + rv = reflect.ValueOf(fn) + } + + rv = indirectInterface(rv) + if !rv.IsValid() { + panic("input func is nil") + } + + typ := rv.Type() + if typ.Kind() != reflect.Func { + basefn.Panicf("non-function of type: %s", typ) + } + + return &FuncX{rv: rv, rt: typ} +} + +// NumIn get the number of func input args +func (f *FuncX) NumIn() int { + return f.rt.NumIn() +} + +// NumOut get the number of func output args +func (f *FuncX) NumOut() int { + return f.rt.NumOut() +} + +// Call the function with given arguments. +// +// Usage: +// +// func main() { +// fn := func(a, b int) int { +// return a + b +// } +// +// fx := NewFunc(fn) +// ret, err := fx.Call(1, 2) +// fmt.Println(ret[0], err) // Output: 3 +// } +func (f *FuncX) Call(args ...any) ([]any, error) { + // convert args to []reflect.Value + argRvs := make([]reflect.Value, len(args)) + for i, arg := range args { + argRvs[i] = reflect.ValueOf(arg) + } + + ret, err := f.CallRV(argRvs) + if err != nil { + return nil, err + } + + // convert ret to []any + rets := make([]any, len(ret)) + for i, r := range ret { + rets[i] = r.Interface() + } + return rets, nil +} + +// Call2 returns the result of evaluating the first argument as a function. +// The function must return 1 result, or 2 results, the second of which is an error. +// +// - Only support func with 1 or 2 return values: (val) OR (val, err) +// - Will check args and try convert input args to func args type. +func (f *FuncX) Call2(args ...any) (any, error) { + // convert args to []reflect.Value + argRvs := make([]reflect.Value, len(args)) + for i, arg := range args { + argRvs[i] = reflect.ValueOf(arg) + } + + if f.TypeChecker == nil { + f.TypeChecker = OneOrTwoOutChecker + } + + // do call func + ret, err := Call(f.rv, argRvs, &f.CallOpt) + if err != nil { + return emptyValue, err + } + + // func return like: (val, err) + if len(ret) == 2 && !ret[1].IsNil() { + return ret[0].Interface(), ret[1].Interface().(error) + } + return ret[0].Interface(), nil +} + +// CallRV call the function with given reflect.Value arguments. +func (f *FuncX) CallRV(args []reflect.Value) ([]reflect.Value, error) { + return Call(f.rv, args, &f.CallOpt) +} + +// WithTypeChecker set type checker +func (f *FuncX) WithTypeChecker(checker TypeCheckerFn) *FuncX { + f.TypeChecker = checker + return f +} + +// WithEnhanceConv set enhance convert +func (f *FuncX) WithEnhanceConv() *FuncX { + f.EnhanceConv = true + return f +} + +// String of func +func (f *FuncX) String() string { + return f.rt.String() +} + +// TypeCheckerFn type checker func +type TypeCheckerFn func(typ reflect.Type) error + +// CallOpt call options +type CallOpt struct { + // TypeChecker check func type before call func. eg: check return values + TypeChecker TypeCheckerFn + // EnhanceConv try to enhance auto convert args to func args type + // - support more type: string, int, uint, float, bool + EnhanceConv bool +} + +// OneOrTwoOutChecker check func type. only allow 1 or 2 return values +// +// Allow func returns: +// - 1 return: (value) +// - 2 return: (value, error) +var OneOrTwoOutChecker = func(typ reflect.Type) error { + if !good1or2outFunc(typ) { + return errors.New("func allow with 1 result or 2 results where the second is an error") + } + return nil +} + +// +// TIP: +// flow func refer from text/template package. +// +// + +// reports whether the function or method has the right result signature. +func good1or2outFunc(typ reflect.Type) bool { + // We allow functions with 1 result or 2 results where the second is an error. + switch { + case typ.NumOut() == 1: + return true + case typ.NumOut() == 2 && typ.Out(1) == errorType: + return true + } + return false +} + +// Call2 returns the result of evaluating the first argument as a function. +// The function must return 1 result, or 2 results, the second of which is an error. +// +// - Only support func with 1 or 2 return values: (val) OR (val, err) +// - Will check args and try convert input args to func args type. +func Call2(fn reflect.Value, args []reflect.Value) (reflect.Value, error) { + ret, err := Call(fn, args, &CallOpt{ + TypeChecker: OneOrTwoOutChecker, + }) + if err != nil { + return emptyValue, err + } + + // func return like: (val, err) + if len(ret) == 2 && !ret[1].IsNil() { + return ret[0], ret[1].Interface().(error) + } + return ret[0], nil +} + +// Call returns the result of evaluating the first argument as a function. +// +// - Will check args and try convert input args to func args type. +// +// from text/template/funcs.go#call +func Call(fn reflect.Value, args []reflect.Value, opt *CallOpt) ([]reflect.Value, error) { + fn = indirectInterface(fn) + if !fn.IsValid() { + return nil, fmt.Errorf("call of nil") + } + + typ := fn.Type() + if typ.Kind() != reflect.Func { + return nil, fmt.Errorf("non-function of type %s", typ) + } + + if opt == nil { + opt = &CallOpt{} + } + if opt.TypeChecker != nil { + if err := opt.TypeChecker(typ); err != nil { + return nil, err + } + } + + numIn := typ.NumIn() + var dddType reflect.Type + if typ.IsVariadic() { + if len(args) < numIn-1 { + return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1) + } + dddType = typ.In(numIn - 1).Elem() + } else { + if len(args) != numIn { + return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn) + } + } + + // Convert each arg to the type of the function's arg. + argv := make([]reflect.Value, len(args)) + for i, arg := range args { + arg = indirectInterface(arg) + // Compute the expected type. Clumsy because of variadic. + argType := dddType + if !typ.IsVariadic() || i < numIn-1 { + argType = typ.In(i) + } + + var err error + if argv[i], err = prepareArg(arg, argType, opt.EnhanceConv); err != nil { + return nil, fmt.Errorf("arg %d: %w", i, err) + } + } + + return SafeCall(fn, argv) +} + +// SafeCall2 runs fun.Call(args), and returns the resulting value and error, if +// any. If the call panics, the panic value is returned as an error. +// +// NOTE: Only support func with 1 or 2 return values: (val) OR (val, err) +// +// from text/template/funcs.go#safeCall +func SafeCall2(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) { + ret, err := SafeCall(fun, args) + if err != nil { + return reflect.Value{}, err + } + + // func return like: (val, err) + if len(ret) == 2 && !ret[1].IsNil() { + return ret[0], ret[1].Interface().(error) + } + return ret[0], nil +} + +// SafeCall runs fun.Call(args), and returns the resulting values, or an error. +// If the call panics, the panic value is returned as an error. +func SafeCall(fun reflect.Value, args []reflect.Value) (ret []reflect.Value, err error) { + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else { + err = fmt.Errorf("%v", r) + } + } + }() + + ret = fun.Call(args) + return +} + +// prepareArg checks if value can be used as an argument of type argType, and +// converts an invalid value to appropriate zero if possible. +func prepareArg(value reflect.Value, argType reflect.Type, enhanced bool) (reflect.Value, error) { + if !value.IsValid() { + if !CanBeNil(argType) { + return emptyValue, fmt.Errorf("value is nil; should be of type %s", argType) + } + + value = reflect.Zero(argType) + } + + if value.Type().AssignableTo(argType) { + return value, nil + } + + // If the argument is an int-like type, and the value is an int-like type, auto-convert. + if IsIntLike(value.Kind()) && IsIntLike(argType.Kind()) && value.Type().ConvertibleTo(argType) { + value = value.Convert(argType) + return value, nil + } + + // enhance convert value to argType, support more type: string, int, uint, float, bool + if enhanced { + return ValueByType(value.Interface(), argType) + } + return emptyValue, fmt.Errorf("value has type %s; should be %s", value.Type(), argType) +} diff --git a/vendor/github.com/gookit/goutil/reflects/map.go b/vendor/github.com/gookit/goutil/reflects/map.go new file mode 100644 index 000000000..b63b9479a --- /dev/null +++ b/vendor/github.com/gookit/goutil/reflects/map.go @@ -0,0 +1,83 @@ +package reflects + +import ( + "reflect" + "strconv" +) + +// EachMap process any map data +func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) { + if fn == nil { + return + } + if mp.Kind() != reflect.Map { + panic("only allow map value data") + } + + for _, key := range mp.MapKeys() { + fn(key, mp.MapIndex(key)) + } +} + +// EachStrAnyMap process any map data as string key and any value +func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) { + EachMap(mp, func(key, val reflect.Value) { + fn(String(key), val.Interface()) + }) +} + +// FlatFunc custom collect handle func +type FlatFunc func(path string, val reflect.Value) + +// FlatMap process tree map to flat key-value map. +// +// Examples: +// +// {"top": {"sub": "value", "sub2": "value2"} } +// -> +// {"top.sub": "value", "top.sub2": "value2" } +func FlatMap(rv reflect.Value, fn FlatFunc) { + if fn == nil { + return + } + + if rv.Kind() != reflect.Map { + panic("only allow flat map data") + } + flatMap(rv, fn, "") +} + +func flatMap(rv reflect.Value, fn FlatFunc, parent string) { + for _, key := range rv.MapKeys() { + path := String(key) + if parent != "" { + path = parent + "." + path + } + + fv := Indirect(rv.MapIndex(key)) + switch fv.Kind() { + case reflect.Map: + flatMap(fv, fn, path) + case reflect.Array, reflect.Slice: + flatSlice(fv, fn, path) + default: + fn(path, fv) + } + } +} + +func flatSlice(rv reflect.Value, fn FlatFunc, parent string) { + for i := 0; i < rv.Len(); i++ { + path := parent + "[" + strconv.Itoa(i) + "]" + fv := Indirect(rv.Index(i)) + + switch fv.Kind() { + case reflect.Map: + flatMap(fv, fn, path) + case reflect.Array, reflect.Slice: + flatSlice(fv, fn, path) + default: + fn(path, fv) + } + } +} diff --git a/vendor/github.com/gookit/goutil/reflects/reflects.go b/vendor/github.com/gookit/goutil/reflects/reflects.go index 2cbdae9cd..cd2ea0eb5 100644 --- a/vendor/github.com/gookit/goutil/reflects/reflects.go +++ b/vendor/github.com/gookit/goutil/reflects/reflects.go @@ -1,2 +1,17 @@ // Package reflects Provide extends reflect util functions. package reflects + +import ( + "fmt" + "reflect" +) + +var emptyValue = reflect.Value{} + +var ( + anyType = reflect.TypeOf((*any)(nil)).Elem() + errorType = reflect.TypeOf((*error)(nil)).Elem() + + fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() + reflectValueType = reflect.TypeOf((*reflect.Value)(nil)).Elem() +) diff --git a/vendor/github.com/gookit/goutil/reflects/slice.go b/vendor/github.com/gookit/goutil/reflects/slice.go new file mode 100644 index 000000000..6332c7a97 --- /dev/null +++ b/vendor/github.com/gookit/goutil/reflects/slice.go @@ -0,0 +1,61 @@ +package reflects + +import ( + "fmt" + "reflect" +) + +// MakeSliceByElem create a new slice by the element type. +// +// - elType: the type of the element. +// - returns: the new slice. +// +// Usage: +// +// sl := MakeSliceByElem(reflect.TypeOf(1), 10, 20) +// sl.Index(0).SetInt(10) +// +// // Or use reflect.AppendSlice() merge two slice +// // Or use `for` with `reflect.Append()` add elements +func MakeSliceByElem(elTyp reflect.Type, len, cap int) reflect.Value { + return reflect.MakeSlice(reflect.SliceOf(elTyp), len, cap) +} + +// FlatSlice flatten multi-level slice to given depth-level slice. +// +// Example: +// +// FlatSlice([]any{ []any{3, 4}, []any{5, 6} }, 1) // Output: []any{3, 4, 5, 6} +// +// always return reflect.Value of []any. note: maybe flatSl.Cap != flatSl.Len +func FlatSlice(sl reflect.Value, depth int) reflect.Value { + items := make([]reflect.Value, 0, sl.Cap()) + slCap := addSliceItem(sl, depth, func(item reflect.Value) { + items = append(items, item) + }) + + flatSl := reflect.MakeSlice(reflect.SliceOf(anyType), 0, slCap) + flatSl = reflect.Append(flatSl, items...) + + return flatSl +} + +func addSliceItem(sl reflect.Value, depth int, collector func(item reflect.Value)) (c int) { + for i := 0; i < sl.Len(); i++ { + v := Elem(sl.Index(i)) + + if depth > 0 { + if v.Kind() != reflect.Slice { + panic(fmt.Sprintf("depth: %d, the value of index %d is not slice", depth, i)) + } + c += addSliceItem(v, depth-1, collector) + } else { + collector(v) + } + } + + if depth == 0 { + c = sl.Cap() + } + return c +} diff --git a/vendor/github.com/gookit/goutil/reflects/type.go b/vendor/github.com/gookit/goutil/reflects/type.go index 064709635..ce0f50e42 100644 --- a/vendor/github.com/gookit/goutil/reflects/type.go +++ b/vendor/github.com/gookit/goutil/reflects/type.go @@ -2,21 +2,28 @@ package reflects import "reflect" -// BKind base data kind type -type BKind uint +// BKind base data kind type, alias of reflect.Kind +// +// Diff with reflect.Kind: +// - Int contains all intX types +// - Uint contains all uintX types +// - Float contains all floatX types +// - Array for array and slice types +// - Complex contains all complexX types +type BKind = reflect.Kind // base kinds const ( // Int for all intX types - Int = BKind(reflect.Int) + Int = reflect.Int // Uint for all uintX types - Uint = BKind(reflect.Uint) + Uint = reflect.Uint // Float for all floatX types - Float = BKind(reflect.Float32) + Float = reflect.Float32 // Array for array,slice types - Array = BKind(reflect.Array) + Array = reflect.Array // Complex for all complexX types - Complex = BKind(reflect.Complex64) + Complex = reflect.Complex64 ) // ToBaseKind convert reflect.Kind to base kind @@ -39,7 +46,7 @@ func ToBKind(kind reflect.Kind) BKind { return Array default: // like: string, map, struct, ptr, func, interface ... - return BKind(kind) + return kind } } @@ -48,6 +55,10 @@ type Type interface { reflect.Type // BaseKind value BaseKind() BKind + // RealType returns a ptr type's real type. otherwise, will return self. + RealType() reflect.Type + // SafeElem returns a type's element type. otherwise, will return self. + SafeElem() reflect.Type } type xType struct { @@ -69,3 +80,13 @@ func TypeOf(v any) Type { func (t *xType) BaseKind() BKind { return t.baseKind } + +// RealType returns a ptr type's real type. otherwise, will return self. +func (t *xType) RealType() reflect.Type { + return TypeReal(t.Type) +} + +// SafeElem returns the array, slice, chan, map type's element type. otherwise, will return self. +func (t *xType) SafeElem() reflect.Type { + return TypeElem(t.Type) +} diff --git a/vendor/github.com/gookit/goutil/reflects/util.go b/vendor/github.com/gookit/goutil/reflects/util.go index 44d17166b..54e7f92af 100644 --- a/vendor/github.com/gookit/goutil/reflects/util.go +++ b/vendor/github.com/gookit/goutil/reflects/util.go @@ -7,28 +7,82 @@ import ( "unsafe" ) +// loopIndirect returns the item at the end of indirection, and a bool to indicate +// if it's nil. If the returned bool is true, the returned value's kind will be +// either a pointer or interface. +func loopIndirect(v reflect.Value) (rv reflect.Value, isNil bool) { + for ; v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface; v = v.Elem() { + if v.IsNil() { + return v, true + } + } + return v, false +} + +// indirectInterface returns the concrete value in an interface value, +// or else the zero reflect.Value. +// That is, if v represents the interface value x, the result is the same as reflect.ValueOf(x): +// the fact that x was an interface value is forgotten. +func indirectInterface(v reflect.Value) reflect.Value { + if v.Kind() != reflect.Interface { + return v + } + if v.IsNil() { + return emptyValue + } + return v.Elem() +} + // Elem returns the value that the interface v contains -// or that the pointer v points to. +// or that the pointer v points to. otherwise, will return self func Elem(v reflect.Value) reflect.Value { - if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + if v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface { return v.Elem() } - - // otherwise, will return self return v } -// Indirect like reflect.Indirect(), but can also indirect reflect.Interface +// Indirect like reflect.Indirect(), but can also indirect reflect.Interface. otherwise, will return self func Indirect(v reflect.Value) reflect.Value { - if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + if v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface { return v.Elem() } - - // otherwise, will return self return v } -// Len get reflect value length +// UnwrapAny unwrap reflect.Interface value. otherwise, will return self +func UnwrapAny(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface { + return v.Elem() + } + + if v.IsNil() { + return emptyValue + } + return v +} + +// TypeReal returns a ptr type's real type. otherwise, will return self. +func TypeReal(t reflect.Type) reflect.Type { + if t.Kind() == reflect.Pointer { + return t.Elem() + } + return t +} + +// TypeElem returns the array, slice, chan, map type's element type. otherwise, will return self. +func TypeElem(t reflect.Type) reflect.Type { + switch t.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + return t.Elem() + default: + return t + } +} + +// Len get reflect value length. allow: intX, uintX, floatX, string, map, array, chan, slice. +// +// Note: (u)intX use width. float to string then calc len. func Len(v reflect.Value) int { v = reflect.Indirect(v) @@ -128,80 +182,3 @@ func SetRValue(rv, val reflect.Value) { rv.Set(val) } - -// EachMap process any map data -func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) { - if fn == nil { - return - } - if mp.Kind() != reflect.Map { - panic("only allow map value data") - } - - for _, key := range mp.MapKeys() { - fn(key, mp.MapIndex(key)) - } -} - -// EachStrAnyMap process any map data as string key and any value -func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) { - EachMap(mp, func(key, val reflect.Value) { - fn(String(key), val.Interface()) - }) -} - -// FlatFunc custom collect handle func -type FlatFunc func(path string, val reflect.Value) - -// FlatMap process tree map to flat key-value map. -// -// Examples: -// -// {"top": {"sub": "value", "sub2": "value2"} } -// -> -// {"top.sub": "value", "top.sub2": "value2" } -func FlatMap(rv reflect.Value, fn FlatFunc) { - if fn == nil { - return - } - - if rv.Kind() != reflect.Map { - panic("only allow flat map data") - } - flatMap(rv, fn, "") -} - -func flatMap(rv reflect.Value, fn FlatFunc, parent string) { - for _, key := range rv.MapKeys() { - path := String(key) - if parent != "" { - path = parent + "." + path - } - - fv := Indirect(rv.MapIndex(key)) - switch fv.Kind() { - case reflect.Map: - flatMap(fv, fn, path) - case reflect.Array, reflect.Slice: - flatSlice(fv, fn, path) - default: - fn(path, fv) - } - } -} - -func flatSlice(rv reflect.Value, fn FlatFunc, parent string) { - for i := 0; i < rv.Len(); i++ { - path := parent + "[" + strconv.Itoa(i) + "]" - fv := Indirect(rv.Index(i)) - - switch fv.Kind() { - case reflect.Map: - flatMap(fv, fn, path) - case reflect.Array, reflect.Slice: - flatSlice(fv, fn, path) - default: - fn(path, fv) - } - } -} diff --git a/vendor/github.com/gookit/goutil/reflects/value.go b/vendor/github.com/gookit/goutil/reflects/value.go index 3b360ada9..bd6bdca85 100644 --- a/vendor/github.com/gookit/goutil/reflects/value.go +++ b/vendor/github.com/gookit/goutil/reflects/value.go @@ -31,7 +31,7 @@ func ValueOf(v any) Value { // Indirect value. alias of the reflect.Indirect() func (v Value) Indirect() Value { - if v.Kind() != reflect.Ptr { + if v.Kind() != reflect.Pointer { return v } @@ -46,9 +46,8 @@ func (v Value) Indirect() Value { // // TIP: not like reflect.Value.Elem. otherwise, will return self. func (v Value) Elem() Value { - if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + if v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface { elem := v.Value.Elem() - return Value{ Value: elem, baseKind: ToBKind(elem.Kind()), diff --git a/vendor/github.com/gookit/goutil/stdio/iface.go b/vendor/github.com/gookit/goutil/stdio/iface.go new file mode 100644 index 000000000..36c28812b --- /dev/null +++ b/vendor/github.com/gookit/goutil/stdio/iface.go @@ -0,0 +1,35 @@ +package stdio + +import "io" + +// Flusher interface +type Flusher interface { + Flush() error +} + +// Syncer interface +type Syncer interface { + Sync() error +} + +// FlushWriter is the interface satisfied by logging destinations. +type FlushWriter interface { + Flusher + // Writer the output writer + io.Writer +} + +// FlushCloseWriter is the interface satisfied by logging destinations. +type FlushCloseWriter interface { + Flusher + // WriteCloser the output writer + io.WriteCloser +} + +// SyncCloseWriter is the interface satisfied by logging destinations. +// such as os.File +type SyncCloseWriter interface { + Syncer + // WriteCloser the output writer + io.WriteCloser +} diff --git a/vendor/github.com/gookit/goutil/stdio/stdio.go b/vendor/github.com/gookit/goutil/stdio/stdio.go index 48f773863..a98b3a002 100644 --- a/vendor/github.com/gookit/goutil/stdio/stdio.go +++ b/vendor/github.com/gookit/goutil/stdio/stdio.go @@ -14,7 +14,7 @@ func DiscardReader(src io.Reader) { _, _ = io.Copy(io.Discard, src) } -// ReadString read contents from io.Reader +// ReadString read contents from io.Reader, return empty string on error func ReadString(r io.Reader) string { bs, err := io.ReadAll(r) if err != nil { @@ -61,28 +61,28 @@ func NewScanner(in any) *bufio.Scanner { } } -// WriteByte to stdout +// WriteByte to stdout, will ignore error func WriteByte(b byte) { _, _ = os.Stdout.Write([]byte{b}) } -// WriteBytes to stdout +// WriteBytes to stdout, will ignore error func WriteBytes(bs []byte) { _, _ = os.Stdout.Write(bs) } -// WritelnBytes to stdout +// WritelnBytes to stdout, will ignore error func WritelnBytes(bs []byte) { _, _ = os.Stdout.Write(bs) _, _ = os.Stdout.Write([]byte("\n")) } -// WriteString to stdout +// WriteString to stdout, will ignore error func WriteString(s string) { _, _ = os.Stdout.WriteString(s) } -// Writeln to stdout +// Writeln string to stdout, will ignore error func Writeln(s string) { _, _ = os.Stdout.WriteString(s) _, _ = os.Stdout.Write([]byte("\n")) diff --git a/vendor/github.com/gookit/goutil/stdio/writer.go b/vendor/github.com/gookit/goutil/stdio/writer.go index 8a9b9fc23..80b70e1e0 100644 --- a/vendor/github.com/gookit/goutil/stdio/writer.go +++ b/vendor/github.com/gookit/goutil/stdio/writer.go @@ -10,6 +10,11 @@ type WriteWrapper struct { Out io.Writer } +// WrapW instance +func WrapW(w io.Writer) *WriteWrapper { + return &WriteWrapper{Out: w} +} + // NewWriteWrapper instance func NewWriteWrapper(w io.Writer) *WriteWrapper { return &WriteWrapper{Out: w} diff --git a/vendor/github.com/gookit/goutil/stdutil/README.md b/vendor/github.com/gookit/goutil/stdutil/README.md deleted file mode 100644 index a554d4689..000000000 --- a/vendor/github.com/gookit/goutil/stdutil/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Std Utils - -- some features - -## Install - -```bash -go get github.com/gookit/goutil/stdutils -``` - -## Go docs - -- [Go docs](https://pkg.go.dev/github.com/gookit/goutil/stdutils) - -## Usage - - -## Testings - -```shell -go test -v ./stdutils/... -``` - -Test limit by regexp: - -```shell -go test -v -run ^TestSetByKeys ./stdutils/... -``` diff --git a/vendor/github.com/gookit/goutil/stdutil/check.go b/vendor/github.com/gookit/goutil/stdutil/check.go deleted file mode 100644 index d1a167b94..000000000 --- a/vendor/github.com/gookit/goutil/stdutil/check.go +++ /dev/null @@ -1,135 +0,0 @@ -package stdutil - -import ( - "reflect" - "strings" - - "github.com/gookit/goutil/reflects" -) - -// IsNil value check -func IsNil(v any) bool { - if v == nil { - return true - } - return reflects.IsNil(reflect.ValueOf(v)) -} - -// IsEmpty value check -func IsEmpty(v any) bool { - if v == nil { - return true - } - return reflects.IsEmpty(reflect.ValueOf(v)) -} - -// IsFunc value -func IsFunc(val any) bool { - if val == nil { - return false - } - return reflect.TypeOf(val).Kind() == reflect.Func -} - -// IsEqual determines if two objects are considered equal. -// -// TIP: cannot compare function type -func IsEqual(src, dst any) bool { - if src == nil || dst == nil { - return src == dst - } - - // cannot compare function type - if IsFunc(src) || IsFunc(dst) { - return false - } - return reflects.IsEqual(src, dst) -} - -// Contains try loop over the data check if the data includes the element. -// alias of the IsContains -// -// TIP: only support types: string, map, array, slice -// -// map - check key exists -// string - check sub-string exists -// array,slice - check sub-element exists -func Contains(data, elem any) bool { - _, found := CheckContains(data, elem) - return found -} - -// IsContains try loop over the data check if the data includes the element. -// -// TIP: only support types: string, map, array, slice -// -// map - check key exists -// string - check sub-string exists -// array,slice - check sub-element exists -func IsContains(data, elem any) bool { - _, found := CheckContains(data, elem) - return found -} - -// CheckContains try loop over the data check if the data includes the element. -// -// TIP: only support types: string, map, array, slice -// -// map - check key exists -// string - check sub-string exists -// array,slice - check sub-element exists -// -// return (false, false) if impossible. -// return (true, false) if element was not found. -// return (true, true) if element was found. -func CheckContains(data, elem any) (valid, found bool) { - dataRv := reflect.ValueOf(data) - dataRt := reflect.TypeOf(data) - if dataRt == nil { - return false, false - } - - dataKind := dataRt.Kind() - - // string - if dataKind == reflect.String { - return true, strings.Contains(dataRv.String(), reflect.ValueOf(elem).String()) - } - - // map - if dataKind == reflect.Map { - mapKeys := dataRv.MapKeys() - for i := 0; i < len(mapKeys); i++ { - if reflects.IsEqual(mapKeys[i].Interface(), elem) { - return true, true - } - } - return true, false - } - - // array, slice - other return false - if dataKind != reflect.Slice && dataKind != reflect.Array { - return false, false - } - - for i := 0; i < dataRv.Len(); i++ { - if reflects.IsEqual(dataRv.Index(i).Interface(), elem) { - return true, true - } - } - return true, false -} - -// ValueIsEmpty reflect value check. -// -// Deprecated: please use reflects.IsEmpty() -func ValueIsEmpty(v reflect.Value) bool { - return reflects.IsEmpty(v) -} - -// ValueLen get reflect value length -// -// Deprecated: please use reflects.Len() -func ValueLen(v reflect.Value) int { - return reflects.Len(v) -} diff --git a/vendor/github.com/gookit/goutil/stdutil/conv.go b/vendor/github.com/gookit/goutil/stdutil/conv.go deleted file mode 100644 index bd5e68dad..000000000 --- a/vendor/github.com/gookit/goutil/stdutil/conv.go +++ /dev/null @@ -1,50 +0,0 @@ -package stdutil - -import ( - "reflect" - - "github.com/gookit/goutil/reflects" - "github.com/gookit/goutil/strutil" -) - -// ToString always convert value to string, will ignore error -func ToString(v any) string { - s, _ := strutil.AnyToString(v, false) - return s -} - -// MustString convert value(basic type) to string, will panic on convert a complex type. -func MustString(v any) string { - s, err := strutil.AnyToString(v, true) - if err != nil { - panic(err) - } - return s -} - -// TryString try to convert a value to string -func TryString(v any) (string, error) { - return strutil.AnyToString(v, true) -} - -// BaseTypeVal convert custom type or intX,uintX,floatX to generic base type. -// -// intX/unitX => int64 -// floatX => float64 -// string => string -// -// returns int64,string,float or error -func BaseTypeVal(val any) (value any, err error) { - return reflects.BaseTypeVal(reflect.ValueOf(val)) -} - -// BaseTypeVal2 convert custom type or intX,uintX,floatX to generic base type. -// -// intX/unitX => int64 -// floatX => float64 -// string => string -// -// returns int64,string,float or error -func BaseTypeVal2(v reflect.Value) (value any, err error) { - return reflects.BaseTypeVal(v) -} diff --git a/vendor/github.com/gookit/goutil/stdutil/stdutil.go b/vendor/github.com/gookit/goutil/stdutil/stdutil.go deleted file mode 100644 index a0382afe0..000000000 --- a/vendor/github.com/gookit/goutil/stdutil/stdutil.go +++ /dev/null @@ -1,34 +0,0 @@ -// Package stdutil provide some standard util functions for go. -package stdutil - -import ( - "fmt" - "runtime" -) - -// DiscardE discard error -func DiscardE(_ error) {} - -// PanicIfErr if error is not empty -func PanicIfErr(err error) { - if err != nil { - panic(err) - } -} - -// PanicIf if error is not empty -func PanicIf(err error) { - if err != nil { - panic(err) - } -} - -// Panicf format panic message use fmt.Sprintf -func Panicf(format string, v ...any) { - panic(fmt.Sprintf(format, v...)) -} - -// GoVersion get go runtime version. eg: "1.18.2" -func GoVersion() string { - return runtime.Version()[2:] -} diff --git a/vendor/github.com/gookit/goutil/stdutil/value.go b/vendor/github.com/gookit/goutil/stdutil/value.go deleted file mode 100644 index 05bf0a514..000000000 --- a/vendor/github.com/gookit/goutil/stdutil/value.go +++ /dev/null @@ -1,8 +0,0 @@ -package stdutil - -import ( - "github.com/gookit/goutil/structs" -) - -// Value data store, is alias of structs.Value -type Value = structs.Value diff --git a/vendor/github.com/gookit/goutil/structs/alias.go b/vendor/github.com/gookit/goutil/structs/alias.go index a25e1bf09..8559c0297 100644 --- a/vendor/github.com/gookit/goutil/structs/alias.go +++ b/vendor/github.com/gookit/goutil/structs/alias.go @@ -52,7 +52,7 @@ func (as *Aliases) HasAlias(alias string) bool { return false } -// ResolveAlias by given name. +// ResolveAlias by given name. if not exists, return the alias self func (as *Aliases) ResolveAlias(alias string) string { if name, ok := as.mapping[alias]; ok { return name diff --git a/vendor/github.com/gookit/goutil/structs/data.go b/vendor/github.com/gookit/goutil/structs/data.go index 9dbe09845..6f574e9d2 100644 --- a/vendor/github.com/gookit/goutil/structs/data.go +++ b/vendor/github.com/gookit/goutil/structs/data.go @@ -12,15 +12,12 @@ import ( // LiteData simple map[string]any struct. no lock type LiteData = Data -// NewLiteData create, not lock +// NewLiteData create, not locked func NewLiteData(data map[string]any) *Data { if data == nil { data = make(map[string]any) } - - return &LiteData{ - data: data, - } + return &LiteData{data: data} } /************************************************************* @@ -82,7 +79,7 @@ func (d *Data) ResetData() { // Merge load new data func (d *Data) Merge(mp map[string]any) { - d.data = maputil.SimpleMerge(d.data, mp) + d.data = maputil.SimpleMerge(mp, d.data) } // Set value to data @@ -151,21 +148,27 @@ func (d *Data) String() string { return maputil.ToString(d.data) } -// OrderedMap data TODO -type OrderedMap struct { +// OrderedData data TODO +type OrderedData struct { maputil.Data - len int + cap int keys []string // vals []any } -// NewOrderedMap instance. -func NewOrderedMap(len int) *OrderedMap { - return &OrderedMap{len: len} +// NewOrderedData instance. +func NewOrderedData(cap int) *OrderedData { + return &OrderedData{cap: cap, Data: make(maputil.Data, cap)} +} + +// Load data +func (om *OrderedData) Load(data map[string]any) { + om.Data.Load(data) + om.keys = om.Data.Keys() } // Set key and value to map -func (om *OrderedMap) Set(key string, val any) { +func (om *OrderedData) Set(key string, val any) { om.keys = append(om.keys, key) om.Data.Set(key, val) } diff --git a/vendor/github.com/gookit/goutil/structs/init.go b/vendor/github.com/gookit/goutil/structs/init.go index 73aec3819..4e55a0b72 100644 --- a/vendor/github.com/gookit/goutil/structs/init.go +++ b/vendor/github.com/gookit/goutil/structs/init.go @@ -4,7 +4,7 @@ import ( "errors" "reflect" - "github.com/gookit/goutil/internal/comfunc" + "github.com/gookit/goutil/internal/varexpr" "github.com/gookit/goutil/reflects" "github.com/gookit/goutil/strutil" ) @@ -89,7 +89,7 @@ func initDefaults(rv reflect.Value, opt *InitOptions) error { continue } - // skip on field has value + // Skip init on field has value. but will check slice and pointer field if !fv.IsZero() { // special: handle for pointer struct field if fv.Kind() == reflect.Pointer { @@ -140,6 +140,11 @@ func initDefaults(rv reflect.Value, opt *InitOptions) error { // init sub struct in slice. like `[]SubStruct` or `[]*SubStruct` if el.Kind() == reflect.Struct { + // up: if slice elem is struct and slice len=0, will be skip init default value + if fv.Len() == 0 { + continue + } + // make sub-struct and init. like: `SubStruct` subFv := reflect.New(el) subFvE := subFv.Elem() @@ -174,7 +179,7 @@ func initDefaultValue(fv reflect.Value, val string, parseEnv bool) error { // parse env var if parseEnv { - val = comfunc.ParseEnvVar(val, nil) + val = varexpr.SafeParse(val) } var anyVal any = val diff --git a/vendor/github.com/gookit/goutil/structs/smap.go b/vendor/github.com/gookit/goutil/structs/smap.go index ada140bd1..c3608ec74 100644 --- a/vendor/github.com/gookit/goutil/structs/smap.go +++ b/vendor/github.com/gookit/goutil/structs/smap.go @@ -1,6 +1,6 @@ package structs -// SMap simple map[string]string struct. +// SMap simple map[string]string struct. TODO type SMap struct { - data map[string]string + data map[string]string //lint:ignore U1000 for unused } diff --git a/vendor/github.com/gookit/goutil/structs/tags.go b/vendor/github.com/gookit/goutil/structs/tags.go index 01ab9ff4d..98eabac7b 100644 --- a/vendor/github.com/gookit/goutil/structs/tags.go +++ b/vendor/github.com/gookit/goutil/structs/tags.go @@ -207,7 +207,6 @@ func ParseTagValueDefault(field, tagVal string) (mp maputil.SMap, err error) { // ParseTagValueQuick quick parse tag value string by sep(;) func ParseTagValueQuick(tagVal string, defines []string) maputil.SMap { parseFn := ParseTagValueDefine(";", defines) - mp, _ := parseFn("", tagVal) return mp } diff --git a/vendor/github.com/gookit/goutil/structs/wrapper.go b/vendor/github.com/gookit/goutil/structs/wrapper.go index 59bfe3b6d..530a848a2 100644 --- a/vendor/github.com/gookit/goutil/structs/wrapper.go +++ b/vendor/github.com/gookit/goutil/structs/wrapper.go @@ -1,14 +1,23 @@ package structs -import "reflect" +import ( + "errors" + "reflect" +) -// Wrapper struct for read or set field value TODO +// Wrapper struct for read or set field value type Wrapper struct { - // src any // source data struct + // src any // source struct + + // reflect.Value of source struct rv reflect.Value // FieldTagName field name for read/write value. default tag: json FieldTagName string + + // caches for field rv and name and tag name TODO + fieldNames []string //lint:ignore U1000 for unused + fvCacheMap map[string]reflect.Value //lint:ignore U1000 for unused } // Wrap create a struct wrapper @@ -27,11 +36,10 @@ func WrapValue(rv reflect.Value) *Wrapper { if rv.Kind() != reflect.Struct { panic("must be provider an struct value") } - return &Wrapper{rv: rv} } -// Get field value by name +// Get field value by name, name allow use dot syntax. func (r *Wrapper) Get(name string) any { val, ok := r.Lookup(name) if !ok { @@ -40,12 +48,30 @@ func (r *Wrapper) Get(name string) any { return val } -// Lookup field value by name +// Lookup field value by name, name allow use dot syntax. func (r *Wrapper) Lookup(name string) (val any, ok bool) { fv := r.rv.FieldByName(name) if !fv.IsValid() { return } - return fv.Interface(), true + if fv.CanInterface() { + return fv.Interface(), true + } + return +} + +// Set field value by name, name allow use dot syntax. +func (r *Wrapper) Set(name string, val any) error { + fv := r.rv.FieldByName(name) + if !fv.IsValid() { + return errors.New("field not found") + } + + if !fv.CanSet() { + return errors.New("field can not set value") + } + + fv.Set(reflect.ValueOf(val)) + return nil } diff --git a/vendor/github.com/gookit/goutil/strutil/check.go b/vendor/github.com/gookit/goutil/strutil/check.go index 8654d8412..4003a2f4d 100644 --- a/vendor/github.com/gookit/goutil/strutil/check.go +++ b/vendor/github.com/gookit/goutil/strutil/check.go @@ -60,6 +60,9 @@ func ContainsByte(s string, c byte) bool { return strings.IndexByte(s, c) >= 0 } +// InArray alias of HasOneSub() +var InArray = HasOneSub + // ContainsOne substr(s) in the given string. alias of HasOneSub() func ContainsOne(s string, subs []string) bool { return HasOneSub(s, subs) } @@ -86,6 +89,9 @@ func HasAllSubs(s string, subs []string) bool { return true } +// StartsWithAny alias of the HasOnePrefix +var StartsWithAny = HasOneSuffix + // IsStartsOf alias of the HasOnePrefix func IsStartsOf(s string, prefixes []string) bool { return HasOnePrefix(s, prefixes) @@ -101,6 +107,9 @@ func HasOnePrefix(s string, prefixes []string) bool { return false } +// StartsWith alias func for HasPrefix +var StartsWith = strings.HasPrefix + // HasPrefix substr in the given string. func HasPrefix(s string, prefix string) bool { return strings.HasPrefix(s, prefix) } diff --git a/vendor/github.com/gookit/goutil/strutil/convbase.go b/vendor/github.com/gookit/goutil/strutil/convbase.go new file mode 100644 index 000000000..d70aff2c4 --- /dev/null +++ b/vendor/github.com/gookit/goutil/strutil/convbase.go @@ -0,0 +1,80 @@ +package strutil + +import ( + "strconv" + "strings" + + "github.com/gookit/goutil/basefn" +) + +// +// -------------------- convert base -------------------- +// + +const ( + Base10Chars = "0123456789" + Base16Chars = "0123456789abcdef" + Base32Chars = "0123456789abcdefghjkmnpqrstvwxyz" + Base36Chars = "0123456789abcdefghijklmnopqrstuvwxyz" + Base62Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + Base64Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" +) + +// Base10Conv convert base 10 string to new base string. +func Base10Conv(src string, to int) string { + return BaseConv(src, 10, to) +} + +// BaseConv convert base string by from and to base. +// +// Note: from and to base must be in [2, 64] +// +// Usage: +// +// BaseConv("123", 10, 16) // Output: "7b" +// BaseConv("7b", 16, 10) // Output: "123" +func BaseConv(src string, from, to int) string { + if from > 64 || from < 2 { + return "" + } + if to > 64 || to < 2 { + return "" + } + return BaseConvByTpl(src, Base64Chars[:from], Base64Chars[:to]) +} + +// BaseConvByTpl convert base string by template. +// +// Usage: +// +// BaseConvert("123", Base62Chars, Base16Chars) // Output: "1e" +// BaseConvert("1e", Base16Chars, Base62Chars) // Output: "123" +func BaseConvByTpl(src string, fromBase, toBase string) string { + if fromBase == toBase { + return src + } + + // convert to base 10 + var dec uint64 = 0 + if fromBase == Base10Chars { + var err error + dec, err = strconv.ParseUint(src, 10, 0) + if err != nil { + basefn.Panicf("input is not a valid decimal number: %s", src) + } + } else { + fLen := uint64(len(fromBase)) + for _, c := range src { + dec = dec*fLen + uint64(strings.IndexRune(fromBase, c)) + } + } + + // convert to new base + var res string + toLen := uint64(len(toBase)) + for dec > 0 { + res = string(toBase[dec%toLen]) + res + dec /= toLen + } + return res +} diff --git a/vendor/github.com/gookit/goutil/strutil/convert.go b/vendor/github.com/gookit/goutil/strutil/convert.go index 067876d40..71ed78a61 100644 --- a/vendor/github.com/gookit/goutil/strutil/convert.go +++ b/vendor/github.com/gookit/goutil/strutil/convert.go @@ -92,51 +92,87 @@ func Implode(sep string, ss ...string) string { return strings.Join(ss, sep) } // String convert value to string, return error on failed func String(val any) (string, error) { - return AnyToString(val, true) + return ToStringWithFunc(val, nil) } // ToString convert value to string, return error on failed func ToString(val any) (string, error) { - return AnyToString(val, true) -} - -// QuietString convert value to string, will ignore error -func QuietString(in any) string { - val, _ := AnyToString(in, false) - return val -} - -// SafeString convert value to string, will ignore error -func SafeString(in any) string { - val, _ := AnyToString(in, false) - return val -} - -// MustString convert value to string, will panic on error -func MustString(in any) string { - val, err := AnyToString(in, false) - if err != nil { - panic(err) - } - return val + return ToStringWithFunc(val, nil) } // StringOrErr convert value to string, return error on failed func StringOrErr(val any) (string, error) { - return AnyToString(val, true) + return ToStringWithFunc(val, nil) } -// AnyToString convert value to string. +// QuietString convert value to string, will ignore error. same as SafeString() +func QuietString(val any) string { + return SafeString(val) +} + +// SafeString convert value to string, will ignore error +func SafeString(in any) string { + val, _ := ToStringWithFunc(in, SprintToStrFunc) + return val +} + +// StringOrPanic convert value to string, will panic on error +func StringOrPanic(val any) string { + return MustString(val) +} + +// MustString convert value to string, will panic on error +func MustString(val any) string { + s, err := ToStringWithFunc(val, nil) + if err != nil { + panic(err) + } + return s +} + +// StringOrDefault convert any value to string, return default value on failed +func StringOrDefault(val any, defVal string) string { + return StringOr(val, defVal) +} + +// StringOr convert any value to string, return default value on failed +func StringOr(val any, defVal string) string { + s, err := ToStringWithFunc(val, nil) + if err != nil { + return defVal + } + return s +} + +// SprintToStrFunc convert any value to string by fmt.Sprint +var SprintToStrFunc = func(v any) (string, error) { + if v == nil { + return "", nil + } + return fmt.Sprint(v), nil +} + +// AnyToString convert any value to string. // // For defaultAsErr: // // - False will use fmt.Sprint convert complex type // - True will return error on fail. -func AnyToString(val any, defaultAsErr bool) (str string, err error) { - if val == nil { - return +func AnyToString(val any, defaultAsErr bool) (s string, err error) { + var fbFunc comdef.ToStringFunc + if !defaultAsErr { + fbFunc = SprintToStrFunc } + return ToStringWithFunc(val, fbFunc) +} + +// ToStringWithFunc convert value to string, with a func to fallback handle. +// +// On not convert: +// - If fbFn is nil, will return comdef.ErrConvType. +// - If fbFn is not nil, will call it to convert. +func ToStringWithFunc(val any, fbFn comdef.ToStringFunc) (str string, err error) { switch value := val.(type) { case int: str = strconv.Itoa(value) @@ -172,16 +208,218 @@ func AnyToString(val any, defaultAsErr bool) (str string, err error) { str = strconv.FormatInt(int64(value), 10) case fmt.Stringer: str = value.String() + case error: + str = value.Error() default: - if defaultAsErr { + if fbFn == nil { err = comdef.ErrConvType } else { - str = fmt.Sprint(value) + str, err = fbFn(value) } } return } +/************************************************************* + * convert string value to bool + *************************************************************/ + +// ToBool convert string to bool +func ToBool(s string) (bool, error) { + return comfunc.StrToBool(strings.TrimSpace(s)) +} + +// QuietBool convert to bool, will ignore error +func QuietBool(s string) bool { + return SafeBool(s) +} + +// SafeBool convert to bool, will ignore error +func SafeBool(s string) bool { + val, _ := comfunc.StrToBool(strings.TrimSpace(s)) + return val +} + +// MustBool convert to bool, will panic on error +func MustBool(s string) bool { + val, err := ToBool(s) + if err != nil { + panic(err) + } + return val +} + +// Bool parse string to bool. like strconv.ParseBool() +func Bool(s string) (bool, error) { + return comfunc.StrToBool(strings.TrimSpace(s)) +} + +/************************************************************* + * convert string value to int + *************************************************************/ + +// Int convert string to int, alias of ToInt() +func Int(s string) (int, error) { + return strconv.Atoi(strings.TrimSpace(s)) +} + +// ToInt convert string to int, return error on fail +func ToInt(s string) (int, error) { + return strconv.Atoi(strings.TrimSpace(s)) +} + +// IntOrDefault convert string to int, return default value on fail +func IntOrDefault(s string, defVal int) int { + return IntOr(s, defVal) +} + +// IntOr convert string to int, return default value on fail +func IntOr(s string, defVal int) int { + val, err := ToInt(s) + if err != nil { + return defVal + } + return val +} + +// SafeInt convert string to int, will ignore error +func SafeInt(s string) int { + val, _ := ToInt(s) + return val +} + +// QuietInt convert string to int, will ignore error +func QuietInt(s string) int { + return SafeInt(s) +} + +// MustInt convert string to int, will panic on error +func MustInt(s string) int { + return IntOrPanic(s) +} + +// IntOrPanic convert value to int, will panic on error +func IntOrPanic(s string) int { + val, err := ToInt(s) + if err != nil { + panic(err) + } + return val +} + +/************************************************************* + * convert string value to int64 + *************************************************************/ + +// Int64 convert string to int, will ignore error +func Int64(s string) int64 { + val, _ := Int64OrErr(s) + return val +} + +// SafeInt64 convert string to int, will ignore error +func SafeInt64(s string) int64 { + val, _ := Int64OrErr(s) + return val +} + +// QuietInt64 convert string to int, will ignore error +func QuietInt64(s string) int64 { + return SafeInt64(s) +} + +// ToInt64 convert string to int, return error on fail +func ToInt64(s string) (int64, error) { + return strconv.ParseInt(s, 10, 0) +} + +// Int64OrDefault convert string to int, return default value on fail +func Int64OrDefault(s string, defVal int64) int64 { + return Int64Or(s, defVal) +} + +// Int64Or convert string to int, return default value on fail +func Int64Or(s string, defVal int64) int64 { + val, err := ToInt64(s) + if err != nil { + return defVal + } + return val +} + +// Int64OrErr convert string to int, return error on fail +func Int64OrErr(s string) (int64, error) { + return strconv.ParseInt(s, 10, 0) +} + +// MustInt64 convert value to int, will panic on error +func MustInt64(s string) int64 { + return Int64OrPanic(s) +} + +// Int64OrPanic convert value to int, will panic on error +func Int64OrPanic(s string) int64 { + val, err := strconv.ParseInt(s, 10, 0) + if err != nil { + panic(err) + } + return val +} + +/************************************************************* + * convert string value to uint + *************************************************************/ + +// Uint convert string to uint, will ignore error +func Uint(s string) uint64 { + val, _ := UintOrErr(s) + return val +} + +// SafeUint convert string to uint, will ignore error +func SafeUint(s string) uint64 { + val, _ := UintOrErr(s) + return val +} + +// ToUint convert string to uint, return error on fail. alias of UintOrErr() +func ToUint(s string) (uint64, error) { + return strconv.ParseUint(s, 10, 0) +} + +// UintOrErr convert string to uint, return error on fail +func UintOrErr(s string) (uint64, error) { + return strconv.ParseUint(s, 10, 0) +} + +// MustUint convert value to uint, will panic on error. alias of UintOrPanic() +func MustUint(s string) uint64 { + return UintOrPanic(s) +} + +// UintOrPanic convert value to uint, will panic on error +func UintOrPanic(s string) uint64 { + val, err := UintOrErr(s) + if err != nil { + panic(err) + } + return val +} + +// UintOrDefault convert string to uint, return default value on fail +func UintOrDefault(s string, defVal uint64) uint64 { + return UintOr(s, defVal) +} + +// UintOr convert string to uint, return default value on fail +func UintOr(s string, defVal uint64) uint64 { + val, err := UintOrErr(s) + if err != nil { + return defVal + } + return val +} + /************************************************************* * convert string value to byte * refer from https://github.com/valyala/fastjson/blob/master/util.go @@ -208,111 +446,6 @@ func ToBytes(s string) (b []byte) { return b } -/************************************************************* - * convert string value to bool - *************************************************************/ - -// ToBool convert string to bool -func ToBool(s string) (bool, error) { - return comfunc.StrToBool(s) -} - -// QuietBool convert to bool, will ignore error -func QuietBool(s string) bool { - val, _ := comfunc.StrToBool(strings.TrimSpace(s)) - return val -} - -// MustBool convert, will panic on error -func MustBool(s string) bool { - val, err := comfunc.StrToBool(strings.TrimSpace(s)) - if err != nil { - panic(err) - } - return val -} - -// Bool parse string to bool. like strconv.ParseBool() -func Bool(s string) (bool, error) { - return comfunc.StrToBool(s) -} - -/************************************************************* - * convert string value to int, float - *************************************************************/ - -// Int convert string to int, alias of ToInt() -func Int(s string) (int, error) { - return strconv.Atoi(strings.TrimSpace(s)) -} - -// ToInt convert string to int, return error on fail -func ToInt(s string) (int, error) { - return strconv.Atoi(strings.TrimSpace(s)) -} - -// Int2 convert string to int, will ignore error -func Int2(s string) int { - val, _ := ToInt(s) - return val -} - -// QuietInt convert string to int, will ignore error -func QuietInt(s string) int { - val, _ := ToInt(s) - return val -} - -// MustInt convert string to int, will panic on error -func MustInt(s string) int { - return IntOrPanic(s) -} - -// IntOrPanic convert value to int, will panic on error -func IntOrPanic(s string) int { - val, err := ToInt(s) - if err != nil { - panic(err) - } - return val -} - -// Int64 convert string to int, will ignore error -func Int64(s string) int64 { - val, _ := Int64OrErr(s) - return val -} - -// QuietInt64 convert string to int, will ignore error -func QuietInt64(s string) int64 { - val, _ := Int64OrErr(s) - return val -} - -// ToInt64 convert string to int, return error on fail -func ToInt64(s string) (int64, error) { - return strconv.ParseInt(s, 10, 0) -} - -// Int64OrErr convert string to int, return error on fail -func Int64OrErr(s string) (int64, error) { - return strconv.ParseInt(s, 10, 0) -} - -// MustInt64 convert value to int, will panic on error -func MustInt64(s string) int64 { - return Int64OrPanic(s) -} - -// Int64OrPanic convert value to int, will panic on error -func Int64OrPanic(s string) int64 { - val, err := strconv.ParseInt(s, 10, 0) - if err != nil { - panic(err) - } - return val -} - /************************************************************* * convert string value to int/string slice, time.Time *************************************************************/ @@ -328,7 +461,7 @@ func ToInts(s string, sep ...string) ([]int, error) { return ToIntSlice(s, sep.. // ToIntSlice split string to slice and convert item to int. // -// Default sep is comma(,) +// Default sep is comma func ToIntSlice(s string, sep ...string) (ints []int, err error) { ss := ToSlice(s, sep...) for _, item := range ss { diff --git a/vendor/github.com/gookit/goutil/strutil/encode.go b/vendor/github.com/gookit/goutil/strutil/encode.go index 70d50a8e1..66e876f64 100644 --- a/vendor/github.com/gookit/goutil/strutil/encode.go +++ b/vendor/github.com/gookit/goutil/strutil/encode.go @@ -94,84 +94,47 @@ func URLDecode(s string) string { // -------------------- base encode -------------------- // +// base32 encoding with no padding +var ( + B32Std = base32.StdEncoding.WithPadding(base32.NoPadding) + B32Hex = base32.HexEncoding.WithPadding(base32.NoPadding) +) + // B32Encode base32 encode func B32Encode(str string) string { - return base32.StdEncoding.EncodeToString([]byte(str)) + return B32Std.EncodeToString([]byte(str)) } // B32Decode base32 decode func B32Decode(str string) string { - dec, _ := base32.StdEncoding.DecodeString(str) + dec, _ := B32Std.DecodeString(str) return string(dec) } +// B64Std base64 encoding with no padding +var B64Std = base64.StdEncoding.WithPadding(base64.NoPadding) + // B64Encode base64 encode func B64Encode(str string) string { - return base64.StdEncoding.EncodeToString([]byte(str)) + return B64Std.EncodeToString([]byte(str)) } // B64EncodeBytes base64 encode func B64EncodeBytes(src []byte) []byte { - buf := make([]byte, base64.StdEncoding.EncodedLen(len(src))) - base64.StdEncoding.Encode(buf, src) - + buf := make([]byte, B64Std.EncodedLen(len(src))) + B64Std.Encode(buf, src) return buf } // B64Decode base64 decode func B64Decode(str string) string { - dec, _ := base64.StdEncoding.DecodeString(str) + dec, _ := B64Std.DecodeString(str) return string(dec) } // B64DecodeBytes base64 decode -func B64DecodeBytes(str string) []byte { - dbuf := make([]byte, base64.StdEncoding.DecodedLen(len(str))) - n, _ := base64.StdEncoding.Decode(dbuf, []byte(str)) - +func B64DecodeBytes(str []byte) []byte { + dbuf := make([]byte, B64Std.DecodedLen(len(str))) + n, _ := B64Std.Decode(dbuf, str) return dbuf[:n] } - -// BaseEncoder interface -type BaseEncoder interface { - Encode(dst []byte, src []byte) - EncodeToString(src []byte) string - Decode(dst []byte, src []byte) (n int, err error) - DecodeString(s string) ([]byte, error) -} - -// BaseType for base encoding -type BaseType uint8 - -// types for base encoding -const ( - BaseTypeStd BaseType = iota - BaseTypeHex - BaseTypeURL - BaseTypeRawStd - BaseTypeRawURL -) - -// Encoding instance -func Encoding(base int, typ BaseType) BaseEncoder { - if base == 32 { - switch typ { - case BaseTypeHex: - return base32.HexEncoding - default: - return base32.StdEncoding - } - } - - // base 64 - switch typ { - case BaseTypeURL: - return base64.URLEncoding - case BaseTypeRawURL: - return base64.RawURLEncoding - case BaseTypeRawStd: - return base64.RawStdEncoding - default: - return base64.StdEncoding - } -} diff --git a/vendor/github.com/gookit/goutil/strutil/ext.go b/vendor/github.com/gookit/goutil/strutil/ext.go index 31134830d..5d2da7d27 100644 --- a/vendor/github.com/gookit/goutil/strutil/ext.go +++ b/vendor/github.com/gookit/goutil/strutil/ext.go @@ -143,3 +143,10 @@ func (b *Builder) WriteStrings(ss ...string) { _, _ = b.Builder.WriteString(s) } } + +// ResetGet return current string and reset builder +func (b *Builder) ResetGet() string { + s := b.String() + b.Reset() + return s +} diff --git a/vendor/github.com/gookit/goutil/strutil/gensn.go b/vendor/github.com/gookit/goutil/strutil/gensn.go new file mode 100644 index 000000000..052ada265 --- /dev/null +++ b/vendor/github.com/gookit/goutil/strutil/gensn.go @@ -0,0 +1,124 @@ +package strutil + +import ( + "hash/crc32" + "math/rand" + "os" + "strconv" + "time" + + "github.com/gookit/goutil/basefn" + "github.com/gookit/goutil/mathutil" +) + +// global id: +// +// https://github.com/rs/xid +// https://github.com/satori/go.uuid +var ( + DefMinInt = 1000 + DefMaxInt = 9999 +) + +// MicroTimeID generate. +// - return like: 16074145697981929446(len: 20) +// +// Conv Base: +// +// mtId := MicroTimeID() // eg: 16935349145643425047 len: 20 +// b16id := Base10Conv(mtId, 16) // eg: eb067252154a9d17 len: 16 +// b32id := Base10Conv(mtId, 32) // eg: em1jia8akl78n len: 13 +// b36id := Base10Conv(mtId, 36) // eg: 3ko088phiuoev len: 13 +// b62id := Base10Conv(mtId, 62) // eg: kb24SKgsQ9V len: 11 +func MicroTimeID() string { + return MTimeBaseID(10) +} + +// MicroTimeHexID micro time hex id generate. +// +// return like: 5b5f0588af1761ad3(len: 16-17) +func MicroTimeHexID() string { return MTimeHexID() } + +// MTimeHexID micro time hex id generate. +// +// return like: 5b5f0588af1761ad3(len: 16-17) +func MTimeHexID() string { + return MTimeBaseID(16) +} + +// MTimeBaseID micro time BASE id generate. toBase: 2 - 36 +// +// Examples: +// - MTimeBaseID(16): 5b5f0588af1761ad3(len: 16-17) +// - MTimeBaseID(36): gorntzvsa73mo(len: 13) +func MTimeBaseID(toBase int) string { + ms := time.Now().UnixMicro() + ri := mathutil.RandomInt(DefMinInt, DefMaxInt) + return strconv.FormatInt(ms, toBase) + strconv.FormatInt(int64(ri), toBase) +} + +// DatetimeNo generate. can use for order-no. +// +// - No prefix, return like: 2023041410484904074285478388(len: 28) +// - With prefix, return like: prefix2023041410484904074285478388(len: 28 + len(prefix)) +func DatetimeNo(prefix string) string { + return DateSN(prefix) +} + +// DateSN generate date serial number. PREFIX + yyyyMMddHHmmss + ext(微秒+随机数) +func DateSN(prefix string) string { + nt := time.Now() + pl := len(prefix) + bs := make([]byte, 0, 28+pl) + if pl > 0 { + bs = append(bs, prefix...) + } + + // micro datetime + bs = nt.AppendFormat(bs, "20060102150405.000000") + bs[14+pl] = '0' + + // host + name, err := os.Hostname() + if err != nil { + name = "default" + } + c32 := crc32.ChecksumIEEE([]byte(name)) // eg: 4006367001 + bs = strconv.AppendUint(bs, uint64(c32%99), 10) + + // rand 1000 - 9999 + rs := rand.New(rand.NewSource(nt.UnixNano())) + bs = strconv.AppendInt(bs, 1000+rs.Int63n(8999), 10) + + return string(bs) +} + +// DateSNV2 generate date serial number. +// - 2 < extBase <= 36 +// - return: PREFIX + yyyyMMddHHmmss + extBase(6bit micro + 5bit random number) +// +// Example: +// - prefix=P, extBase=16, return: P2023091414361354b4490(len=22) +// - prefix=P, extBase=36, return: P202309141436131gw3jg(len=21) +func DateSNV2(prefix string, extBase ...int) string { + pl := len(prefix) + bs := make([]byte, 0, 22+pl) + if pl > 0 { + bs = append(bs, prefix...) + } + + // micro datetime + nt := time.Now() + bs = nt.AppendFormat(bs, "20060102150405.000000") + + // rand 10000 - 99999 + rs := rand.New(rand.NewSource(nt.UnixNano())) + // 6bit micro + 5bit rand + ext := strconv.AppendInt(bs[16+pl:], 10000+rs.Int63n(89999), 10) + + base := basefn.FirstOr(extBase, 16) + // prefix + yyyyMMddHHmmss + ext(convert to base) + bs = append(bs[:14+pl], strconv.FormatInt(SafeInt64(string(ext)), base)...) + + return string(bs) +} diff --git a/vendor/github.com/gookit/goutil/strutil/crypto.go b/vendor/github.com/gookit/goutil/strutil/hash.go similarity index 78% rename from vendor/github.com/gookit/goutil/strutil/crypto.go rename to vendor/github.com/gookit/goutil/strutil/hash.go index 7c5337118..9cfa239fc 100644 --- a/vendor/github.com/gookit/goutil/strutil/crypto.go +++ b/vendor/github.com/gookit/goutil/strutil/hash.go @@ -2,15 +2,15 @@ package strutil import ( "crypto/hmac" - "crypto/md5" "crypto/sha256" "encoding/hex" - "fmt" + + "github.com/gookit/goutil/byteutil" ) // Md5 Generate a 32-bit md5 string func Md5(src any) string { - return hex.EncodeToString(Md5Bytes(src)) + return string(Md5Bytes(src)) } // MD5 Generate a 32-bit md5 string @@ -21,13 +21,12 @@ func GenMd5(src any) string { return Md5(src) } // Md5Bytes Generate a 32-bit md5 bytes func Md5Bytes(src any) []byte { - h := md5.New() - if s, ok := src.(string); ok { - h.Write([]byte(s)) - } else { - h.Write([]byte(fmt.Sprint(src))) - } - return h.Sum(nil) + return byteutil.Md5(src) +} + +// ShortMd5 Generate a 16-bit md5 string. remove first 8 and last 8 bytes from 32-bit md5 string. +func ShortMd5(src any) string { + return string(byteutil.ShortMd5(src)) } // HashPasswd for quick hash an input password string diff --git a/vendor/github.com/gookit/goutil/strutil/id.go b/vendor/github.com/gookit/goutil/strutil/id.go deleted file mode 100644 index 0e8fe6526..000000000 --- a/vendor/github.com/gookit/goutil/strutil/id.go +++ /dev/null @@ -1,69 +0,0 @@ -package strutil - -import ( - "hash/crc32" - "math/rand" - "os" - "strconv" - "time" - - "github.com/gookit/goutil/mathutil" -) - -// global id: -// -// https://github.com/rs/xid -// https://github.com/satori/go.uuid -var ( - DefMinInt = 1000 - DefMaxInt = 9999 -) - -// MicroTimeID generate. -// return like: 16074145697981929446(len: 20) -func MicroTimeID() string { - ms := time.Now().UnixNano() / 1000 - ri := mathutil.RandomInt(DefMinInt, DefMaxInt) - - return strconv.FormatInt(ms, 10) + strconv.FormatInt(int64(ri), 10) -} - -// MicroTimeHexID generate. -// return like: 5b5f0588af1761ad3(len: 16-17) -func MicroTimeHexID() string { - ms := time.Now().UnixNano() / 1000 - ri := mathutil.RandomInt(DefMinInt, DefMaxInt) - - return strconv.FormatInt(ms, 16) + strconv.FormatInt(int64(ri), 16) -} - -// DatetimeNo generate. can use for order-no. -// -// - No prefix, return like: 2023041410484904074285478388(len: 28) -// - With prefix, return like: prefix2023041410484904074285478388(len: 28 + len(prefix)) -func DatetimeNo(prefix string) string { - nt := time.Now() - pl := len(prefix) - bs := make([]byte, 0, 28+pl) - if pl > 0 { - bs = append(bs, prefix...) - } - - // micro datatime - bs = nt.AppendFormat(bs, "20060102150405.000000") - bs[14+pl] = '0' - - // host - name, err := os.Hostname() - if err != nil { - name = "default" - } - c32 := crc32.ChecksumIEEE([]byte(name)) // eg: 4006367001 - bs = strconv.AppendUint(bs, uint64(c32%99), 10) - - // rand 10000 - 99999 - rand.Seed(nt.UnixNano()) - bs = strconv.AppendInt(bs, 10000+rand.Int63n(89999), 10) - - return string(bs) -} diff --git a/vendor/github.com/gookit/goutil/strutil/padding.go b/vendor/github.com/gookit/goutil/strutil/padding.go index 30cb042cc..dea9cbe0f 100644 --- a/vendor/github.com/gookit/goutil/strutil/padding.go +++ b/vendor/github.com/gookit/goutil/strutil/padding.go @@ -61,13 +61,12 @@ func Resize(s string, length int, align PosFlag) string { } if align == PosMiddle { - strLn := len(s) - padLn := (length - strLn) / 2 - padStr := string(make([]byte, padLn)) - + padLn := (length - len(s)) / 2 if diff := length - padLn*2; diff > 0 { s += " " } + + padStr := string(RepeatBytes(' ', padLn)) return padStr + s + padStr } @@ -85,15 +84,19 @@ func PadChars[T byte | rune](cs []T, pad T, length int, pos PosFlag) []T { idx := length - ln ns := make([]T, length) - ps := RepeatChars(pad, idx) if pos == PosRight { copy(ns, cs) - copy(ns[idx:], ps) - } else { // to left - copy(ns[:idx], ps) - copy(ns[idx:], cs) + for i := ln; i < length; i++ { + ns[i] = pad + } + return ns } + // to left + for i := 0; i < idx; i++ { + ns[i] = pad + } + copy(ns[idx:], cs) return ns } @@ -131,32 +134,29 @@ func PadRunesRight(rs []rune, pad rune, length int) []rune { * String repeat operation *************************************************************/ -// Repeat a string +// Repeat a string by given times. func Repeat(s string, times int) string { - if times <= 0 { + if times < 1 { return "" } if times == 1 { return s } - ss := make([]string, 0, times) - for i := 0; i < times; i++ { - ss = append(ss, s) - } + var sb strings.Builder + sb.Grow(len(s) * times) - return strings.Join(ss, "") + for i := 0; i < times; i++ { + sb.WriteString(s) + } + return sb.String() } // RepeatRune repeat a rune char. -func RepeatRune(char rune, times int) []rune { - return RepeatChars(char, times) -} +func RepeatRune(char rune, times int) []rune { return RepeatChars(char, times) } // RepeatBytes repeat a byte char. -func RepeatBytes(char byte, times int) []byte { - return RepeatChars(char, times) -} +func RepeatBytes(char byte, times int) []byte { return RepeatChars(char, times) } // RepeatChars repeat a byte char. func RepeatChars[T byte | rune](char T, times int) []T { @@ -164,9 +164,9 @@ func RepeatChars[T byte | rune](char T, times int) []T { return make([]T, 0) } - chars := make([]T, 0, times) + chars := make([]T, times) for i := 0; i < times; i++ { - chars = append(chars, char) + chars[i] = char } return chars } diff --git a/vendor/github.com/gookit/goutil/strutil/parse.go b/vendor/github.com/gookit/goutil/strutil/parse.go index 82fd51920..ccabb19f3 100644 --- a/vendor/github.com/gookit/goutil/strutil/parse.go +++ b/vendor/github.com/gookit/goutil/strutil/parse.go @@ -23,7 +23,7 @@ func MustToTime(s string, layouts ...string) time.Time { // key is layout length. var layoutMap = map[int][]string{ 6: {"200601", "060102", time.Kitchen}, - 8: {"20060102"}, + 8: {"20060102", "06-01-02"}, 10: {"2006-01-02"}, 13: {"2006-01-02 15"}, 15: {time.Stamp}, @@ -49,7 +49,7 @@ func ToTime(s string, layouts ...string) (t time.Time, err error) { // custom layout if len(layouts) > 0 { if len(layouts[0]) > 0 { - return time.Parse(layouts[0], s) + return time.ParseInLocation(layouts[0], s, time.Local) } err = ErrDateLayout @@ -81,7 +81,7 @@ func ToTime(s string, layouts ...string) (t time.Time, err error) { layout = strings.Replace(layout, "-", "/", -1) } - t, err = time.Parse(layout, s) + t, err = time.ParseInLocation(layout, s, time.Local) if err == nil { return } diff --git a/vendor/github.com/gookit/goutil/strutil/random.go b/vendor/github.com/gookit/goutil/strutil/random.go index fe404a017..7a00141ad 100644 --- a/vendor/github.com/gookit/goutil/strutil/random.go +++ b/vendor/github.com/gookit/goutil/strutil/random.go @@ -1,17 +1,17 @@ package strutil import ( - "encoding/base64" - mathRand "math/rand" + mRand "math/rand" "time" "github.com/gookit/goutil/byteutil" + "github.com/gookit/goutil/encodes" ) // some consts string chars const ( Numbers = "0123456789" - HexChars = "0123456789abcdef" + HexChars = "0123456789abcdef" // base16 AlphaBet = "abcdefghijklmnopqrstuvwxyz" AlphaBet1 = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" @@ -19,70 +19,51 @@ const ( AlphaNum = "abcdefghijklmnopqrstuvwxyz0123456789" AlphaNum2 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" AlphaNum3 = "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" - - Base62Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - Base64Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" ) +func newRand() *mRand.Rand { + return mRand.New(mRand.NewSource(time.Now().UnixNano())) +} + // RandomChars generate give length random chars at `a-z` func RandomChars(ln int) string { cs := make([]byte, ln) - for i := 0; i < ln; i++ { - // 1607400451937462000 - mathRand.Seed(time.Now().UnixNano()) - idx := mathRand.Intn(25) // 0 - 25 - cs[i] = AlphaBet[idx] - } + // UnixNano: 1607400451937462000 + rn := newRand() + for i := 0; i < ln; i++ { + // rand in 0 - 25 + cs[i] = AlphaBet[rn.Intn(25)] + } return string(cs) } // RandomCharsV2 generate give length random chars in `0-9a-z` func RandomCharsV2(ln int) string { cs := make([]byte, ln) - for i := 0; i < ln; i++ { - // 1607400451937462000 - mathRand.Seed(time.Now().UnixNano()) - idx := mathRand.Intn(35) // 0 - 35 - cs[i] = AlphaNum[idx] - } + // UnixNano: 1607400451937462000 + rn := newRand() + for i := 0; i < ln; i++ { + // rand in 0 - 35 + cs[i] = AlphaNum[rn.Intn(35)] + } return string(cs) } // RandomCharsV3 generate give length random chars in `0-9a-zA-Z` func RandomCharsV3(ln int) string { cs := make([]byte, ln) + // UnixNano: 1607400451937462000 + rn := newRand() + for i := 0; i < ln; i++ { - // 1607400451937462000 - mathRand.Seed(time.Now().UnixNano()) - idx := mathRand.Intn(61) // 0 - 61 - cs[i] = AlphaNum2[idx] + // rand in 0 - 61 + cs[i] = AlphaNum2[rn.Intn(61)] } - return string(cs) } -// RandomBytes generate -func RandomBytes(length int) ([]byte, error) { - return byteutil.Random(length) -} - -// RandomString generate. -// -// Example: -// -// // this will give us a 44 byte, base64 encoded output -// token, err := RandomString(32) -// if err != nil { -// // Serve an appropriately vague error to the -// // user, but log the details internally. -// } -func RandomString(length int) (string, error) { - b, err := RandomBytes(length) - return base64.URLEncoding.EncodeToString(b), err -} - // RandWithTpl generate random string with give template func RandWithTpl(n int, letters string) string { if len(letters) == 0 { @@ -91,11 +72,27 @@ func RandWithTpl(n int, letters string) string { ln := len(letters) cs := make([]byte, n) - for i := 0; i < n; i++ { - mathRand.Seed(int64(time.Now().Nanosecond())) - idx := mathRand.Intn(ln) - cs[i] = letters[idx] - } + rn := newRand() + for i := 0; i < n; i++ { + // rand in 0 - ln + cs[i] = letters[rn.Intn(ln)] + } return byteutil.String(cs) } + +// RandomString generate. +// +// Example: +// +// // this will give us a 44 byte, base64 encoded output +// token, err := RandomString(16) // eg: "I7S4yFZddRMxQoudLZZ-eg" +func RandomString(length int) (string, error) { + b, err := RandomBytes(length) + return encodes.B64URL.EncodeToString(b), err +} + +// RandomBytes generate +func RandomBytes(length int) ([]byte, error) { + return byteutil.Random(length) +} diff --git a/vendor/github.com/gookit/goutil/strutil/runes.go b/vendor/github.com/gookit/goutil/strutil/runes.go index 7acb46d80..246ad64ad 100644 --- a/vendor/github.com/gookit/goutil/strutil/runes.go +++ b/vendor/github.com/gookit/goutil/strutil/runes.go @@ -74,9 +74,9 @@ func Utf8Width(s string) int { return RunesWidth([]rune(s)) } // // str := "hi,你好" // -// strutil.Utf8Width(str) => 7 -// len(str) => 9 -// len([]rune(str)) = utf8.RuneCountInString(s) => 5 +// len(str) // 9 +// strutil.Utf8Width(str) // 7 +// len([]rune(str)) = utf8.RuneCountInString(s) // 5 func RunesWidth(rs []rune) (w int) { if len(rs) == 0 { return diff --git a/vendor/github.com/gookit/goutil/strutil/split.go b/vendor/github.com/gookit/goutil/strutil/split.go index 807139e67..1062ef7d4 100644 --- a/vendor/github.com/gookit/goutil/strutil/split.go +++ b/vendor/github.com/gookit/goutil/strutil/split.go @@ -2,6 +2,38 @@ package strutil import "strings" +// BeforeFirst get substring before first sep. +func BeforeFirst(s, sep string) string { + if i := strings.Index(s, sep); i >= 0 { + return s[:i] + } + return s +} + +// AfterFirst get substring after first sep. +func AfterFirst(s, sep string) string { + if i := strings.Index(s, sep); i >= 0 { + return s[i+len(sep):] + } + return "" +} + +// BeforeLast get substring before last sep. +func BeforeLast(s, sep string) string { + if i := strings.LastIndex(s, sep); i >= 0 { + return s[:i] + } + return s +} + +// AfterLast get substring after last sep. +func AfterLast(s, sep string) string { + if i := strings.LastIndex(s, sep); i >= 0 { + return s[i+len(sep):] + } + return "" +} + /************************************************************* * String split operation *************************************************************/ diff --git a/vendor/github.com/gookit/goutil/strutil/strutil.go b/vendor/github.com/gookit/goutil/strutil/strutil.go index f90229343..e81253f90 100644 --- a/vendor/github.com/gookit/goutil/strutil/strutil.go +++ b/vendor/github.com/gookit/goutil/strutil/strutil.go @@ -8,6 +8,8 @@ import ( "fmt" "strings" "text/template" + + "github.com/gookit/goutil/comdef" ) // OrCond return s1 on cond is True, OR return s2. @@ -19,7 +21,32 @@ func OrCond(cond bool, s1, s2 string) string { return s2 } -// OrElse return s OR orVal(new-value) on s is empty +// BlankOr return default value on val is blank, otherwise return val +func BlankOr(val, defVal string) string { + val = strings.TrimSpace(val) + if val != "" { + return val + } + return defVal +} + +// ZeroOr return default value on val is zero, otherwise return val. same of OrElse() +func ZeroOr[T ~string](val, defVal T) T { + if val != "" { + return val + } + return defVal +} + +// ErrorOr return default value on err is not nil, otherwise return s +// func ErrorOr(s string, err error, defVal string) string { +// if err != nil { +// return defVal +// } +// return s +// } + +// OrElse return default value on s is empty, otherwise return s func OrElse(s, orVal string) string { if s != "" { return s @@ -28,7 +55,7 @@ func OrElse(s, orVal string) string { } // OrHandle return fn(s) on s is not empty. -func OrHandle(s string, fn func(s string) string) string { +func OrHandle(s string, fn comdef.StringHandleFunc) string { if s != "" { return fn(s) } @@ -72,35 +99,41 @@ func PrettyJSON(v any) (string, error) { return string(out), err } -// RenderTemplate render text template +var builtInFuncs = template.FuncMap{ + // don't escape content + "raw": func(s string) string { + return s + }, + "trim": func(s string) string { + return strings.TrimSpace(s) + }, + // join strings + "join": func(ss []string, sep string) string { + return strings.Join(ss, sep) + }, + // lower first char + "lcFirst": func(s string) string { + return LowerFirst(s) + }, + // upper first char + "upFirst": func(s string) string { + return UpperFirst(s) + }, +} + +// RenderTemplate quickly render text template. +// +// Deprecated: please use textutil.RenderTpl() instead it func RenderTemplate(input string, data any, fns template.FuncMap, isFile ...bool) string { return RenderText(input, data, fns, isFile...) } -// RenderText render text template +// RenderText quickly render text template +// +// Deprecated: please use textutil.RenderTpl() instead it func RenderText(input string, data any, fns template.FuncMap, isFile ...bool) string { t := template.New("simple-text") - t.Funcs(template.FuncMap{ - // don't escape content - "raw": func(s string) string { - return s - }, - "trim": func(s string) string { - return strings.TrimSpace(s) - }, - // join strings - "join": func(ss []string, sep string) string { - return strings.Join(ss, sep) - }, - // lower first char - "lcFirst": func(s string) string { - return LowerFirst(s) - }, - // upper first char - "upFirst": func(s string) string { - return UpperFirst(s) - }, - }) + t.Funcs(builtInFuncs) // add custom template functions if len(fns) > 0 { @@ -131,11 +164,12 @@ func WrapTag(s, tag string) string { // SubstrCount returns the number of times the substr substring occurs in the s string. // Actually, it comes from strings.Count(). -// s The string to search in -// substr The substring to search for -// params[0] The offset where to start counting. -// params[1] The maximum length after the specified offset to search for the substring. -func SubstrCount(s string, substr string, params ...uint64) (int, error) { +// +// - s The string to search in +// - substr The substring to search for +// - params[0] The offset where to start counting. +// - params[1] The maximum length after the specified offset to search for the substring. +func SubstrCount(s, substr string, params ...uint64) (int, error) { larg := len(params) hasArgs := larg != 0 if hasArgs && larg > 2 { @@ -144,9 +178,11 @@ func SubstrCount(s string, substr string, params ...uint64) (int, error) { if !hasArgs { return strings.Count(s, substr), nil } + strlen := len(s) offset := 0 end := strlen + if hasArgs { offset = int(params[0]) if larg == 2 { @@ -157,6 +193,7 @@ func SubstrCount(s string, substr string, params ...uint64) (int, error) { end = strlen } } + s = string([]rune(s)[offset:end]) return strings.Count(s, substr), nil } diff --git a/vendor/github.com/gookit/goutil/strutil/textutil/litetpl.go b/vendor/github.com/gookit/goutil/strutil/textutil/litetpl.go new file mode 100644 index 000000000..e9faeccf4 --- /dev/null +++ b/vendor/github.com/gookit/goutil/strutil/textutil/litetpl.go @@ -0,0 +1,277 @@ +package textutil + +import ( + "fmt" + "io" + "regexp" + "strings" + "text/template" + + "github.com/gookit/goutil/arrutil" + "github.com/gookit/goutil/basefn" + "github.com/gookit/goutil/fsutil" + "github.com/gookit/goutil/reflects" + "github.com/gookit/goutil/structs" + "github.com/gookit/goutil/strutil" +) + +// LTemplateOptFn lite template option func +type LTemplateOptFn func(opt *LiteTemplateOpt) + +// LiteTemplateOpt template options for LiteTemplate +type LiteTemplateOpt struct { + // func name alias map. eg: {"up_first": "upFirst"} + nameMp structs.Aliases + Funcs template.FuncMap + + Left, Right string + + ParseDef bool + ParseEnv bool +} + +// SetVarFmt custom sets the variable format in template +func (o *LiteTemplateOpt) SetVarFmt(varFmt string) { + o.Left, o.Right = strutil.TrimCut(varFmt, ",") +} + +// LiteTemplate implement a simple text template engine. +// +// - support parse template vars +// - support access multi-level map field. eg: {{ user.name }} +// - support parse default value +// - support parse env vars +// - support custom pipeline func handle. eg: {{ name | upper }} {{ name | def:guest }} +// +// NOTE: not support control flow, eg: if/else/for/with +type LiteTemplate struct { + LiteTemplateOpt + vr VarReplacer + // template func map. refer the text/template + // + // Func allow return 1 or 2 values, if return 2 values, the second value is error. + fxs map[string]*reflects.FuncX +} + +// NewLiteTemplate instance +func NewLiteTemplate(opFns ...LTemplateOptFn) *LiteTemplate { + st := &LiteTemplate{ + fxs: make(map[string]*reflects.FuncX), + // with default options + LiteTemplateOpt: LiteTemplateOpt{ + Left: "{{", + Right: "}}", + ParseDef: true, + ParseEnv: true, + }, + } + + st.vr.RenderFn = st.renderVars + for _, fn := range opFns { + fn(&st.LiteTemplateOpt) + } + + st.Init() + return st +} + +// Init LiteTemplate +func (t *LiteTemplate) Init() { + if t.vr.init { + return + } + + // init var replacer + t.vr.init = true + t.initReplacer(&t.vr) + + // add built-in funcs + t.AddFuncs(builtInFuncs) + t.nameMp.AddAliasMap(map[string]string{ + "up_first": "upFirst", + "lc_first": "lcFirst", + "def": "default", + }) + + // add custom funcs + if len(t.Funcs) > 0 { + t.AddFuncs(t.Funcs) + } +} + +func (t *LiteTemplate) initReplacer(vr *VarReplacer) { + vr.flatSubs = true + vr.parseDef = t.ParseDef + vr.parseEnv = t.ParseEnv + vr.Left, vr.Right = t.Left, t.Right + basefn.PanicIf(vr.Right == "", "var format right chars is required") + + vr.lLen, vr.rLen = len(vr.Left), len(vr.Right) + rightLast := string(vr.Right[vr.rLen-1]) // 排除匹配,防止匹配到类似 "{} adb ddf {var}" + + // eg: \{(?s:([^\}]+?))\} + // (?s:...) - 让 "." 匹配换行 + // (?s:(.+?)) - 第二个 "?" 非贪婪匹配 + pattern := regexp.QuoteMeta(vr.Left) + `(?s:([^` + regexp.QuoteMeta(rightLast) + `]+?))` + regexp.QuoteMeta(vr.Right) + vr.varReg = regexp.MustCompile(pattern) +} + +// AddFuncs add custom template functions +func (t *LiteTemplate) AddFuncs(fns map[string]any) { + for name, fn := range fns { + t.fxs[name] = reflects.NewFunc(fn) + } +} + +// RenderString render template string with vars +func (t *LiteTemplate) RenderString(s string, vars map[string]any) string { + return t.vr.Replace(s, vars) +} + +// RenderFile render template file with vars +func (t *LiteTemplate) RenderFile(filePath string, vars map[string]any) (string, error) { + // read file contents + s, err := fsutil.ReadStringOrErr(filePath) + if err != nil { + return "", err + } + + return t.vr.Replace(s, vars), nil +} + +// RenderWrite render template string with vars, and write result to writer +func (t *LiteTemplate) RenderWrite(wr io.Writer, s string, vars map[string]any) error { + s = t.vr.Replace(s, vars) + _, err := io.WriteString(wr, s) + return err +} + +func (t *LiteTemplate) renderVars(s string, varMap map[string]string) string { + return t.vr.varReg.ReplaceAllStringFunc(s, func(sub string) string { + // var name or pipe expression. + name := strings.TrimSpace(sub[t.vr.lLen : len(sub)-t.vr.rLen]) + name = strings.TrimLeft(name, "$.") + + var defVal string + var pipes []string + if strings.ContainsRune(name, '|') { + pipes = strutil.Split(name, "|") + // compatible default value. eg: {{ name | inhere }} + if len(pipes) == 2 && !strings.ContainsRune(pipes[1], ':') && !t.isFunc(pipes[1]) { + name, defVal = pipes[0], pipes[1] + pipes = nil // clear pipes + } else { // collect pipe functions + name, pipes = pipes[0], pipes[1:] + } + } + + if val, ok := varMap[name]; ok { + if len(pipes) > 0 { + var err error + val, err = t.applyPipes(val, pipes) + if err != nil { + return fmt.Sprintf("Render var %q error: %v", name, err) + } + } + return val + } + + // var not found + if len(defVal) > 0 { + return defVal + } + + if t.vr.NotFound != nil { + if val, ok := t.vr.NotFound(name); ok { + return val + } + } + + // check is default func. eg: {{ name | def:guest }} + if len(pipes) == 1 && strings.ContainsRune(pipes[0], ':') { + fName, argVal := strutil.TrimCut(pipes[0], ":") + if t.isDefaultFunc(fName) { + return argVal + } + } + + t.vr.missVars = append(t.vr.missVars, name) + return sub + }) +} + +func (t *LiteTemplate) applyPipes(val any, pipes []string) (string, error) { + var err error + + // pipe expr: "trim|upper|substr:1,2" + // => + // pipes: ["trim", "upper", "substr:1,2"] + for _, name := range pipes { + args := []any{val} + + // has custom args. eg: "substr:1,2" + if strings.ContainsRune(name, ':') { + var argStr string + name, argStr = strutil.TrimCut(name, ":") + + if otherArgs := parseArgStr(argStr); len(otherArgs) > 0 { + args = append(args, otherArgs...) + } + } + + name = t.nameMp.ResolveAlias(name) + + // call pipe func + if fx, ok := t.fxs[name]; ok { + val, err = fx.Call2(args...) + if err != nil { + return "", err + } + } else { + return "", fmt.Errorf("template func %q not found", name) + } + } + + return strutil.ToString(val) +} + +func (t *LiteTemplate) isFunc(name string) bool { + _, ok := t.fxs[name] + if !ok { + // check name alias + return t.nameMp.HasAlias(name) + } + return ok +} + +func (t *LiteTemplate) isDefaultFunc(name string) bool { + return name == "default" || name == "def" +} + +var stdTpl = NewLiteTemplate() + +// RenderFile render template file with vars +func RenderFile(filePath string, vars map[string]any) (string, error) { + return stdTpl.RenderFile(filePath, vars) +} + +// RenderString render str template string or file. +func RenderString(input string, data map[string]any) string { + return stdTpl.RenderString(input, data) +} + +// RenderWrite render template string with vars, and write result to writer +func RenderWrite(wr io.Writer, s string, vars map[string]any) error { + return stdTpl.RenderWrite(wr, s, vars) +} + +func parseArgStr(argStr string) (ss []any) { + if argStr == "" { // no arg + return + } + + if len(argStr) == 1 { // one char + return []any{argStr} + } + return arrutil.StringsToAnys(strutil.Split(argStr, ",")) +} diff --git a/vendor/github.com/gookit/goutil/strutil/textutil/texttpl.go b/vendor/github.com/gookit/goutil/strutil/textutil/texttpl.go new file mode 100644 index 000000000..ba4d50971 --- /dev/null +++ b/vendor/github.com/gookit/goutil/strutil/textutil/texttpl.go @@ -0,0 +1,90 @@ +package textutil + +import ( + "bytes" + "io" + "strings" + "text/template" + + "github.com/gookit/goutil" + "github.com/gookit/goutil/basefn" + "github.com/gookit/goutil/fsutil" + "github.com/gookit/goutil/strutil" +) + +var builtInFuncs = template.FuncMap{ + // don't escape content + "raw": func(s string) string { + return s + }, + "trim": strings.TrimSpace, + // lower first char + "lcFirst": strutil.LowerFirst, + // upper first char + "upFirst": strutil.UpperFirst, + // upper case + "upper": strings.ToUpper, + // lower case + "lower": strings.ToLower, + // cut sub-string + "substr": strutil.Substr, + // default value + "default": func(v, defVal any) string { + if goutil.IsEmpty(v) { + return strutil.SafeString(defVal) + } + return strutil.SafeString(v) + }, + // join strings + "join": func(ss []string, sep string) string { + return strings.Join(ss, sep) + }, +} + +// TextRenderOpt render text template options +type TextRenderOpt struct { + // Output use custom output writer + Output io.Writer + // Funcs add custom template functions + Funcs template.FuncMap +} + +// RenderOptFn render option func +type RenderOptFn func(opt *TextRenderOpt) + +// NewRenderOpt create a new render options +func NewRenderOpt(optFns []RenderOptFn) *TextRenderOpt { + opt := &TextRenderOpt{} + for _, fn := range optFns { + fn(opt) + } + return opt +} + +// RenderGoTpl render input text or template file. +func RenderGoTpl(input string, data any, optFns ...RenderOptFn) string { + opt := NewRenderOpt(optFns) + + t := template.New("text-renderer") + t.Funcs(builtInFuncs) + if len(opt.Funcs) > 0 { + t.Funcs(opt.Funcs) + } + + if !strings.Contains(input, "{{") && fsutil.IsFile(input) { + template.Must(t.ParseFiles(input)) + } else { + template.Must(t.Parse(input)) + } + + // use custom output writer + if opt.Output != nil { + basefn.MustOK(t.Execute(opt.Output, data)) + return "" // return empty string + } + + // use buffer receive rendered content + buf := new(bytes.Buffer) + basefn.MustOK(t.Execute(buf, data)) + return buf.String() +} diff --git a/vendor/github.com/gookit/goutil/strutil/textutil/var_replacer.go b/vendor/github.com/gookit/goutil/strutil/textutil/var_replacer.go index 29ef2c3d4..748245943 100644 --- a/vendor/github.com/gookit/goutil/strutil/textutil/var_replacer.go +++ b/vendor/github.com/gookit/goutil/strutil/textutil/var_replacer.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/gookit/goutil/arrutil" - "github.com/gookit/goutil/internal/comfunc" + "github.com/gookit/goutil/internal/varexpr" "github.com/gookit/goutil/maputil" "github.com/gookit/goutil/strutil" ) @@ -33,11 +33,17 @@ type VarReplacer struct { keepMissVars bool // missing vars list missVars []string - // NotFound handler + // NotFound hook func. on var-name not found NotFound FallbackFn + // RenderFn custom render func + RenderFn func(s string, vs map[string]string) string } -// NewVarReplacer instance +// NewVarReplacer instance. +// +// Usage: +// +// rpl := NewVarReplacer("{{,}}") func NewVarReplacer(format string, opFns ...func(vp *VarReplacer)) *VarReplacer { vp := &VarReplacer{flatSubs: true} for _, fn := range opFns { @@ -46,7 +52,11 @@ func NewVarReplacer(format string, opFns ...func(vp *VarReplacer)) *VarReplacer return vp.WithFormat(format) } -// NewFullReplacer instance +// NewFullReplacer instance. will enable parse env and parse default. +// +// Usage: +// +// rpl := NewFullReplacer("{{,}}") func NewFullReplacer(format string) *VarReplacer { return NewVarReplacer(format, func(vp *VarReplacer) { vp.WithParseEnv().WithParseDefault().KeepMissingVars() @@ -90,8 +100,8 @@ func (r *VarReplacer) WithFormat(format string) *VarReplacer { return r } -// Init var matcher -func (r *VarReplacer) Init() *VarReplacer { +// Init var replacer +func (r *VarReplacer) Init() { if !r.init { r.lLen, r.rLen = len(r.Left), len(r.Right) if r.Right != "" { @@ -100,9 +110,9 @@ func (r *VarReplacer) Init() *VarReplacer { // no right tag. eg: $name, $user.age r.varReg = regexp.MustCompile(regexp.QuoteMeta(r.Left) + `(\w[\w-]*(?:\.[\w-]+)*)`) } - } - return r + r.init = true + } } // ParseVars the text contents and collect vars @@ -114,13 +124,13 @@ func (r *VarReplacer) ParseVars(s string) []string { return arrutil.Unique(ss) } -// Render any-map vars in the text contents -func (r *VarReplacer) Render(s string, tplVars map[string]any) string { - return r.Replace(s, tplVars) -} - // Replace any-map vars in the text contents func (r *VarReplacer) Replace(s string, tplVars map[string]any) string { + return r.Render(s, tplVars) +} + +// Render any-map vars in the text contents +func (r *VarReplacer) Render(s string, tplVars map[string]any) string { if !strings.Contains(s, r.Left) { return s } @@ -128,14 +138,15 @@ func (r *VarReplacer) Replace(s string, tplVars map[string]any) string { return s } - var varMap map[string]string + r.Init() + var varMap map[string]string if r.flatSubs { varMap = make(map[string]string, len(tplVars)*2) maputil.FlatWithFunc(tplVars, func(path string, val reflect.Value) { if val.Kind() == reflect.String { if r.parseEnv { - varMap[path] = comfunc.ParseEnvVar(val.String(), nil) + varMap[path] = varexpr.SafeParse(val.String()) } else { varMap[path] = val.String() } @@ -147,7 +158,7 @@ func (r *VarReplacer) Replace(s string, tplVars map[string]any) string { varMap = maputil.ToStringMap(tplVars) } - return r.Init().doReplace(s, varMap) + return r.doReplace(s, varMap) } // ReplaceSMap string-map vars in the text contents @@ -163,11 +174,12 @@ func (r *VarReplacer) RenderSimple(s string, varMap map[string]string) string { if r.parseEnv { for name, val := range varMap { - varMap[name] = comfunc.ParseEnvVar(val, nil) + varMap[name] = varexpr.SafeParse(val) } } - return r.Init().doReplace(s, varMap) + r.Init() + return r.doReplace(s, varMap) } // MissVars list @@ -186,6 +198,11 @@ func (r *VarReplacer) doReplace(s string, varMap map[string]string) string { r.missVars = make([]string, 0) // clear on each replace } + // use custom render func + if r.RenderFn != nil { + return r.RenderFn(s, varMap) + } + return r.varReg.ReplaceAllStringFunc(s, func(sub string) string { name := strings.TrimSpace(sub[r.lLen : len(sub)-r.rLen]) diff --git a/vendor/github.com/gookit/goutil/syncs/chan.go b/vendor/github.com/gookit/goutil/syncs/chan.go new file mode 100644 index 000000000..ac89e8cd7 --- /dev/null +++ b/vendor/github.com/gookit/goutil/syncs/chan.go @@ -0,0 +1,35 @@ +package syncs + +import ( + "os" + "os/signal" + "syscall" +) + +// WaitCloseSignals for some huang program. +// +// Usage: +// +// // do something. eg: start a http server +// +// syncs.WaitCloseSignals(func(sig os.Signal) { +// // do something +// }) +func WaitCloseSignals(onClose func(sig os.Signal)) { + signals := make(chan os.Signal, 1) + signal.Notify(signals, os.Interrupt, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) + + // block until a signal is received. + onClose(<-signals) +} + +// Go is a basic promise implementation: it wraps calls a function in a goroutine +// and returns a channel which will later return the function's return value. +func Go(f func() error) error { + ch := make(chan error) + go func() { + ch <- f() + }() + + return <-ch +} diff --git a/vendor/github.com/gookit/goutil/syncs/group.go b/vendor/github.com/gookit/goutil/syncs/group.go new file mode 100644 index 000000000..2a41aa5bb --- /dev/null +++ b/vendor/github.com/gookit/goutil/syncs/group.go @@ -0,0 +1,46 @@ +package syncs + +import ( + "context" + + "golang.org/x/sync/errgroup" +) + +// ErrGroup is a collection of goroutines working on subtasks that +// are part of the same overall task. +// +// Refers: +// +// https://github.com/neilotoole/errgroup +// https://github.com/fatih/semgroup +type ErrGroup struct { + *errgroup.Group +} + +// NewCtxErrGroup instance +func NewCtxErrGroup(ctx context.Context, limit ...int) (*ErrGroup, context.Context) { + egg, ctx1 := errgroup.WithContext(ctx) + if len(limit) > 0 && limit[0] > 0 { + egg.SetLimit(limit[0]) + } + + eg := &ErrGroup{Group: egg} + return eg, ctx1 +} + +// NewErrGroup instance +func NewErrGroup(limit ...int) *ErrGroup { + eg := &ErrGroup{Group: new(errgroup.Group)} + + if len(limit) > 0 && limit[0] > 0 { + eg.SetLimit(limit[0]) + } + return eg +} + +// Add one or more handler at once +func (g *ErrGroup) Add(handlers ...func() error) { + for _, handler := range handlers { + g.Go(handler) + } +} diff --git a/vendor/github.com/gookit/goutil/stdutil/chan.go b/vendor/github.com/gookit/goutil/syncs/signal.go similarity index 65% rename from vendor/github.com/gookit/goutil/stdutil/chan.go rename to vendor/github.com/gookit/goutil/syncs/signal.go index 084835f71..41f032ce0 100644 --- a/vendor/github.com/gookit/goutil/stdutil/chan.go +++ b/vendor/github.com/gookit/goutil/syncs/signal.go @@ -1,34 +1,12 @@ -package stdutil +package syncs import ( "context" "fmt" - "io" "os" "os/signal" - "syscall" ) -// WaitCloseSignals for some huang program. -func WaitCloseSignals(closer io.Closer) error { - signals := make(chan os.Signal, 1) - signal.Notify(signals, os.Interrupt, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) - <-signals - - return closer.Close() -} - -// Go is a basic promise implementation: it wraps calls a function in a goroutine -// and returns a channel which will later return the function's return value. -func Go(f func() error) error { - ch := make(chan error) - go func() { - ch <- f() - }() - - return <-ch -} - // SignalHandler returns an actor, i.e. an execute and interrupt func, that // terminates with SignalError when the process receives one of the provided // signals, or the parent context is canceled. diff --git a/vendor/github.com/gookit/goutil/syncs/syncs.go b/vendor/github.com/gookit/goutil/syncs/syncs.go new file mode 100644 index 000000000..45164de73 --- /dev/null +++ b/vendor/github.com/gookit/goutil/syncs/syncs.go @@ -0,0 +1,2 @@ +// Package syncs provides synchronization primitives util functions. +package syncs diff --git a/vendor/github.com/gookit/goutil/sysutil/sysgo.go b/vendor/github.com/gookit/goutil/sysutil/sysgo.go index 4bafcdc38..a4c4dd758 100644 --- a/vendor/github.com/gookit/goutil/sysutil/sysgo.go +++ b/vendor/github.com/gookit/goutil/sysutil/sysgo.go @@ -1,10 +1,9 @@ package sysutil import ( - "errors" - "regexp" "runtime" - "strings" + + "github.com/gookit/goutil/goinfo" ) // GoVersion get go runtime version. eg: "1.18.2" @@ -12,22 +11,10 @@ func GoVersion() string { return runtime.Version()[2:] } -// GoInfo define -// -// On os by: -// -// go env GOVERSION GOOS GOARCH -// go version // "go version go1.19 darwin/amd64" -type GoInfo struct { - Version string - GoOS string - Arch string -} +// GoInfo define. alias of goinfo.GoInfo +type GoInfo = goinfo.GoInfo -// match "go version go1.19 darwin/amd64" -var goVerRegex = regexp.MustCompile(`\sgo([\d.]+)\s(\w+)/(\w+)`) - -// ParseGoVersion get info by parse `go version` results. +// ParseGoVersion get info by parse `go version` results. alias of goinfo.ParseGoVersion() // // Examples: // @@ -39,38 +26,10 @@ var goVerRegex = regexp.MustCompile(`\sgo([\d.]+)\s(\w+)/(\w+)`) // info, err := sysutil.ParseGoVersion() // dump.P(info) func ParseGoVersion(line string) (*GoInfo, error) { - // eg: [" go1.19 darwin/amd64", "1.19", "darwin", "amd64"] - lines := goVerRegex.FindStringSubmatch(line) - if len(lines) != 4 { - return nil, errors.New("returns go info is not full") - } - - info := &GoInfo{} - info.Version = strings.TrimPrefix(lines[1], "go") - info.GoOS = lines[2] - info.Arch = lines[3] - - return info, nil + return goinfo.ParseGoVersion(line) } -// OsGoInfo fetch and parse +// OsGoInfo fetch and parse. alias of goinfo.OsGoInfo() func OsGoInfo() (*GoInfo, error) { - cmdArgs := []string{"env", "GOVERSION", "GOOS", "GOARCH"} - line, err := ExecCmd("go", cmdArgs) - if err != nil { - return nil, err - } - - lines := strings.Split(strings.TrimSpace(line), "\n") - - if len(lines) != len(cmdArgs)-1 { - return nil, errors.New("returns go info is not full") - } - - info := &GoInfo{} - info.Version = strings.TrimPrefix(lines[0], "go") - info.GoOS = lines[1] - info.Arch = lines[2] - - return info, nil + return goinfo.OsGoInfo() } diff --git a/vendor/github.com/gookit/goutil/sysutil/user_nonwin.go b/vendor/github.com/gookit/goutil/sysutil/user_nonwin.go index db5a00ee1..e8d613c7b 100644 --- a/vendor/github.com/gookit/goutil/sysutil/user_nonwin.go +++ b/vendor/github.com/gookit/goutil/sysutil/user_nonwin.go @@ -9,14 +9,21 @@ import ( ) // ChangeUserByName change work user by new username. -func ChangeUserByName(newUname string) (err error) { +func ChangeUserByName(newUname string) error { u := MustFindUser(newUname) // syscall.Setlogin(newUname) - return ChangeUserUidGid(strutil.IntOrPanic(u.Uid), strutil.IntOrPanic(u.Gid)) + return ChangeUserUIDGid(strutil.IntOrPanic(u.Uid), strutil.IntOrPanic(u.Gid)) } // ChangeUserUidGid change work user by new username uid,gid -func ChangeUserUidGid(newUID int, newGid int) (err error) { +// +// Deprecated: use ChangeUserUIDGid instead +func ChangeUserUidGid(newUID int, newGid int) error { + return ChangeUserUIDGid(newUID, newGid) +} + +// ChangeUserUIDGid change work user by new username uid,gid +func ChangeUserUIDGid(newUID int, newGid int) (err error) { if newUID > 0 { err = syscall.Setuid(newUID) diff --git a/vendor/github.com/gookit/goutil/sysutil/user_windows.go b/vendor/github.com/gookit/goutil/sysutil/user_windows.go index 0ad7322bf..4d3ea34a9 100644 --- a/vendor/github.com/gookit/goutil/sysutil/user_windows.go +++ b/vendor/github.com/gookit/goutil/sysutil/user_windows.go @@ -5,10 +5,17 @@ package sysutil // ChangeUserByName change work user by new username. func ChangeUserByName(newUname string) (err error) { - return ChangeUserUidGid(0, 0) + return ChangeUserUIDGid(0, 0) } // ChangeUserUidGid change work user by new username uid,gid +// +// Deprecated: use ChangeUserUIDGid instead func ChangeUserUidGid(newUid int, newGid int) (err error) { + return ChangeUserUIDGid(newUid, newGid) +} + +// ChangeUserUIDGid change work user by new username uid,gid +func ChangeUserUIDGid(newUid int, newGid int) (err error) { return nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index 03e4771ce..e2cc47604 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1004,8 +1004,8 @@ github.com/gobwas/pool/pbytes ## explicit github.com/gobwas/ws github.com/gobwas/ws/wsutil -# github.com/goccy/go-yaml v1.11.0 -## explicit; go 1.18 +# github.com/goccy/go-yaml v1.11.2 +## explicit; go 1.19 github.com/goccy/go-yaml github.com/goccy/go-yaml/ast github.com/goccy/go-yaml/internal/errors @@ -1086,34 +1086,38 @@ github.com/google/renameio/v2 # github.com/google/uuid v1.4.0 ## explicit github.com/google/uuid -# github.com/gookit/color v1.5.3 +# github.com/gookit/color v1.5.4 ## explicit; go 1.18 github.com/gookit/color -# github.com/gookit/config/v2 v2.2.3 -## explicit; go 1.18 +# github.com/gookit/config/v2 v2.2.4 +## explicit; go 1.19 github.com/gookit/config/v2 github.com/gookit/config/v2/yaml -# github.com/gookit/goutil v0.6.10 -## explicit; go 1.18 +# github.com/gookit/goutil v0.6.14 +## explicit; go 1.19 github.com/gookit/goutil github.com/gookit/goutil/arrutil github.com/gookit/goutil/basefn github.com/gookit/goutil/byteutil github.com/gookit/goutil/cliutil/cmdline github.com/gookit/goutil/comdef +github.com/gookit/goutil/encodes github.com/gookit/goutil/envutil github.com/gookit/goutil/errorx github.com/gookit/goutil/fsutil +github.com/gookit/goutil/goinfo +github.com/gookit/goutil/internal/checkfn github.com/gookit/goutil/internal/comfunc +github.com/gookit/goutil/internal/varexpr github.com/gookit/goutil/jsonutil github.com/gookit/goutil/maputil github.com/gookit/goutil/mathutil github.com/gookit/goutil/reflects github.com/gookit/goutil/stdio -github.com/gookit/goutil/stdutil github.com/gookit/goutil/structs github.com/gookit/goutil/strutil github.com/gookit/goutil/strutil/textutil +github.com/gookit/goutil/syncs github.com/gookit/goutil/sysutil github.com/gookit/goutil/sysutil/cmdr # github.com/gorilla/handlers v1.5.1