mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-04-30 20:23:26 -04:00
Update github.com/gookit/goutil to v0.7.4 for FreeBSD compatibility
The goutil that OpenCloud currently uses is one version from the release that adds FreeBSD support, this now compiles successfully on FreeBSD.
This commit is contained in:
2
go.mod
2
go.mod
@@ -241,7 +241,7 @@ require (
|
||||
github.com/google/go-tpm v0.9.8 // indirect
|
||||
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect
|
||||
github.com/google/renameio/v2 v2.0.2 // indirect
|
||||
github.com/gookit/goutil v0.7.1 // indirect
|
||||
github.com/gookit/goutil v0.7.4 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/schema v1.4.1 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -589,8 +589,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gookit/config/v2 v2.2.7 h1:P58/uENzkDp7r7Hp8YSZxOhZ/F5a5Y/AzyhDUkQYa9A=
|
||||
github.com/gookit/config/v2 v2.2.7/go.mod h1:QST99HmkZXXD/HkZmOm1OXpgdAnc6Rl9syGl+u62Pi8=
|
||||
github.com/gookit/goutil v0.7.1 h1:AaFJPN9mrdeYBv8HOybri26EHGCC34WJVT7jUStGJsI=
|
||||
github.com/gookit/goutil v0.7.1/go.mod h1:vJS9HXctYTCLtCsZot5L5xF+O1oR17cDYO9R0HxBmnU=
|
||||
github.com/gookit/goutil v0.7.4 h1:OWgUngToNz+bPlX5aP+EMG31DraEU63uvKMwwT3vseM=
|
||||
github.com/gookit/goutil v0.7.4/go.mod h1:vJS9HXctYTCLtCsZot5L5xF+O1oR17cDYO9R0HxBmnU=
|
||||
github.com/gookit/ini/v2 v2.3.2 h1:W6tzOGE6zOLQelH2xhcH8BIBZPtnEpJgQ+J6SsAKBSw=
|
||||
github.com/gookit/ini/v2 v2.3.2/go.mod h1:StKSqY5niArRwYBS8Z71+iWUt5ow47qt359sS9YQLYY=
|
||||
github.com/gophercloud/gophercloud v0.15.1-0.20210202035223-633d73521055/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
|
||||
|
||||
2
vendor/github.com/gookit/goutil/.gitignore
generated
vendored
2
vendor/github.com/gookit/goutil/.gitignore
generated
vendored
@@ -18,7 +18,9 @@
|
||||
*.out
|
||||
*.cov
|
||||
.DS_Store
|
||||
.xenv.toml
|
||||
|
||||
*~
|
||||
.claude/
|
||||
testdata/
|
||||
vendor/
|
||||
206
vendor/github.com/gookit/goutil/README.md
generated
vendored
206
vendor/github.com/gookit/goutil/README.md
generated
vendored
@@ -1,4 +1,4 @@
|
||||
# Go Util
|
||||
# GoUtil
|
||||
|
||||

|
||||
[](https://github.com/gookit/goutil)
|
||||
@@ -7,7 +7,7 @@
|
||||
[](https://coveralls.io/github/gookit/goutil?branch=master)
|
||||
[](https://pkg.go.dev/github.com/gookit/goutil)
|
||||
|
||||
💪 Useful utils(**800+**) package for the Go: int, string, array/slice, map, error, time, format, CLI, ENV, filesystem, system, testing and more.
|
||||
💪 Useful utils(**900+**) package for the Go: int, string, array/slice, map, struct, reflect, error, time, format, CLI, ENV, filesystem, system, testing and more.
|
||||
|
||||
> **[中文说明](README.zh-CN.md)**
|
||||
|
||||
@@ -52,8 +52,8 @@
|
||||
- [`encodes`](encodes): Provide some encoding/decoding, hash, crypto util functions. eg: base64, hex, etc.
|
||||
- [`finder`](x/finder) Provides a simple and convenient file/dir lookup function, supports filtering, excluding, matching, ignoring, etc.
|
||||
- [`netutil`](netutil) Network util functions. eg: Ip, IpV4, IpV6, Mac, Port, Hostname, etc.
|
||||
- [textutil](strutil/textutil) Provide some extensions text handle util functions. eg: text replace, etc.
|
||||
- [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.
|
||||
- [`textscan`](strutil/textscan) Implemented a parser that quickly scans and analyzes text content. It can be used to parse INI, Properties and other formats
|
||||
- [`cmdr`](sysutil/cmdr) Provide for quick build and run a cmd, batch run multi cmd tasks
|
||||
- [`clipboard`](x/clipboard) Provide a simple clipboard read and write operations.
|
||||
- [`process`](sysutil/process) Provide some process handle util functions.
|
||||
@@ -63,7 +63,7 @@
|
||||
## Go Doc
|
||||
|
||||
Please see [Go doc](https://pkg.go.dev/github.com/gookit/goutil).
|
||||
Wiki docs on [DeepWiki - gookit/goutil](https://deepwiki.com/gookit/goutil)
|
||||
Wiki docs on [ZRead.ai - gookit/goutil](https://zread.ai/gookit/goutil)
|
||||
|
||||
## Install
|
||||
|
||||
@@ -109,6 +109,8 @@ dump.Print(somevar, somevar2, ...)
|
||||
|
||||
> Package `github.com/gookit/goutil/arrutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at arrutil/arrutil.go
|
||||
func GetRandomOne[T any](arr []T) T
|
||||
@@ -152,6 +154,7 @@ 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 ToMap[T any, K comdef.ScalarType, V any](list []T, mapFn func(T) (K, V)) map[K]V
|
||||
func AnyToSlice(sl any) (ls []any, err error)
|
||||
func AnyToStrings(arr any) []string
|
||||
func MustToStrings(arr any) []string
|
||||
@@ -171,7 +174,8 @@ func FormatIndent(arr any, indent string) string
|
||||
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 Map[T, V any](list []T, mapFn MapFn[T, V]) []V
|
||||
func Map1[T, R any](list []T, fn func(t T) R) []R
|
||||
func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V
|
||||
func Unique[T comdef.NumberOrString](list []T) []T
|
||||
func IndexOf[T comdef.NumberOrString](val T, list []T) int
|
||||
@@ -189,6 +193,8 @@ 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
|
||||
```
|
||||
</details>
|
||||
|
||||
#### ArrUtil Usage
|
||||
|
||||
**check value**:
|
||||
@@ -211,10 +217,13 @@ ss, err := arrutil.ToStrings([]int{1, 2}) // ss: []string{"1", "2"}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Bytes Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/byteutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at byteutil/buffer.go
|
||||
func NewBuffer() *Buffer
|
||||
@@ -244,18 +253,22 @@ func NewStdEncoder(encFn BytesEncodeFunc, decFn BytesDecodeFunc) *StdEncoder
|
||||
// source at byteutil/pool.go
|
||||
func NewChanPool(chSize int, width int, capWidth int) *ChanPool
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Cflag
|
||||
|
||||
> Package `github.com/gookit/goutil/cflag`
|
||||
|
||||
`cflag` - Wraps and extends go `flag.FlagSet` to build simple command line applications
|
||||
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at cflag/app.go
|
||||
func NewApp(fns ...func(app *App)) *App
|
||||
func NewCmd(name, desc string, runFunc ...func(c *Cmd) error) *Cmd
|
||||
// source at cflag/cflag.go
|
||||
func SetDebug(open bool)
|
||||
func New(fns ...func(c *CFlags)) *CFlags
|
||||
func NewWith(name, version, desc string, 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)
|
||||
@@ -269,6 +282,8 @@ func Value
|
||||
// source at cflag/optarg.go
|
||||
func NewArg(name, desc string, required bool) *FlagArg
|
||||
// source at cflag/util.go
|
||||
func SetDebug(open bool)
|
||||
func DebugMsg(format string, args ...any)
|
||||
func IsGoodName(name string) bool
|
||||
func IsZeroValue(opt *flag.Flag, value string) (bool, bool)
|
||||
func AddPrefix(name string) string
|
||||
@@ -280,15 +295,20 @@ func IsFlagHelpErr(err error) bool
|
||||
func WrapColorForCode(s string) string
|
||||
func ReplaceShorts(args []string, shortsMap map[string]string) []string
|
||||
```
|
||||
</details>
|
||||
|
||||
#### `cflag` Usage
|
||||
|
||||
`cflag` usage please see [cflag/README.md](cflag/README.md)
|
||||
|
||||
|
||||
|
||||
### CLI Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/cliutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at cliutil/cliutil.go
|
||||
func SplitMulti(ss []string, sep string) []string
|
||||
@@ -325,6 +345,8 @@ func InputIsYes(ans string) bool
|
||||
func ByteIsYes(ans byte) bool
|
||||
func ReadPassword(question ...string) string
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
#### CLI Util Usage
|
||||
|
||||
@@ -381,10 +403,13 @@ Build line: ./myapp -a val0 -m "this is message" arg0
|
||||
|
||||
> More, please see [./cliutil/README](cliutil/README.md)
|
||||
|
||||
|
||||
### Var Dumper
|
||||
|
||||
> Package `github.com/gookit/goutil/dump`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at dump/dump.go
|
||||
func Std() *Dumper
|
||||
@@ -411,7 +436,10 @@ func WithoutPosition() OptionFunc
|
||||
func WithoutOutput(out io.Writer) OptionFunc
|
||||
func WithoutColor() OptionFunc
|
||||
func WithoutType() OptionFunc
|
||||
func WithoutLen() OptionFunc
|
||||
```
|
||||
</details>
|
||||
|
||||
#### Examples
|
||||
|
||||
example code:
|
||||
@@ -456,10 +484,13 @@ Preview:
|
||||

|
||||
|
||||
|
||||
|
||||
### ENV/Environment
|
||||
|
||||
> Package `github.com/gookit/goutil/envutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at envutil/envutil.go
|
||||
func VarReplace(s string) string
|
||||
@@ -503,6 +534,8 @@ func UnsetEnvs(keys ...string)
|
||||
func LoadText(text string)
|
||||
func LoadString(line string) bool
|
||||
```
|
||||
</details>
|
||||
|
||||
#### ENV Util Usage
|
||||
|
||||
**helper functions:**
|
||||
@@ -522,12 +555,17 @@ envutil.ParseValue("${ENV_NAME | defValue}")
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Errorx
|
||||
|
||||
> Package `github.com/gookit/goutil/errorx`
|
||||
|
||||
Package errorx provide a enhanced error implements, allow with call stack and wrap another error.
|
||||
`errorx` provides an enhanced error reporting implementation that contains call stack information and can wrap the previous level of error.
|
||||
|
||||
> Additional call stack information is included when printing errors, making it easy to log and find problems.
|
||||
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at errorx/assert.go
|
||||
@@ -578,6 +616,8 @@ func Is(err, target error) bool
|
||||
func To(err error, target any) bool
|
||||
func As(err error, target any) bool
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
#### Errorx Usage
|
||||
|
||||
@@ -655,16 +695,23 @@ runtime.goexit()
|
||||
```
|
||||
|
||||
|
||||
|
||||
### File System
|
||||
|
||||
> Package `github.com/gookit/goutil/fsutil`
|
||||
|
||||
Package `fsutil` Filesystem util functions: quick check, create, read and write file. eg: file and dir check, operate
|
||||
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```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 IsSymlink(path string) bool
|
||||
func IsAbsPath(aPath string) bool
|
||||
func IsEmptyDir(dirPath string) bool
|
||||
func IsImageFile(path string) bool
|
||||
@@ -680,6 +727,10 @@ 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 FindAllInParentDirs(dirPath, name string, optFns ...FindParentOptFn) []string
|
||||
func FindOneInParentDirs(dirPath, name string, optFns ...FindParentOptFn) string
|
||||
func FindNameInParentDirs(dirPath, name string, collectFn func(fullPath string), optFns ...FindParentOptFn)
|
||||
func FindInParentDirs(dirPath string, matchFunc func(dir string) bool, maxLevel int)
|
||||
func SearchNameUp(dirPath, name string) string
|
||||
func SearchNameUpx(dirPath, name string) (string, bool)
|
||||
func WalkDir(dir string, fn fs.WalkDirFunc) error
|
||||
@@ -713,9 +764,12 @@ func FileExt(fPath string) string
|
||||
func Extname(fPath string) string
|
||||
func Suffix(fPath string) string
|
||||
func Expand(pathStr string) string
|
||||
func ExpandHome(pathStr string) string
|
||||
func ExpandPath(pathStr string) string
|
||||
func ResolvePath(pathStr string) string
|
||||
func SplitPath(pathStr string) (dir, name string)
|
||||
func UserHomeDir() string
|
||||
func HomeDir() string
|
||||
// source at fsutil/info_nonwin.go
|
||||
func Realpath(pathStr string) string
|
||||
// source at fsutil/mime.go
|
||||
@@ -723,9 +777,11 @@ 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 Mkdir(dirPath string, perm fs.FileMode) error
|
||||
func MkdirQuick(dirPath string) error
|
||||
func EnsureDir(path string) error
|
||||
func MkDirs(perm fs.FileMode, dirPaths ...string) error
|
||||
func MkSubDirs(perm fs.FileMode, parentDir string, subDirs ...string) error
|
||||
func MkParentDir(fpath string) error
|
||||
func NewOpenOption(optFns ...OpenOptionFunc) *OpenOption
|
||||
func OpenOptOrNew(opt *OpenOption) *OpenOption
|
||||
@@ -779,7 +835,10 @@ 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
|
||||
func CreateSymlink(target, linkPath string) error
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
#### FsUtil Usage
|
||||
|
||||
@@ -811,6 +870,7 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
### JSON Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/jsonutil`
|
||||
@@ -841,10 +901,13 @@ func IsObject(s string) bool
|
||||
func StripComments(src string) string
|
||||
```
|
||||
|
||||
### Map
|
||||
|
||||
### Maputil
|
||||
|
||||
> Package `github.com/gookit/goutil/maputil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at maputil/check.go
|
||||
func HasKey(mp, key any) (ok bool)
|
||||
@@ -890,6 +953,7 @@ func Merge1level(mps ...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 MergeStrMap(src, dst map[string]string) map[string]string
|
||||
func AppendSMap(dst, src map[string]string) map[string]string
|
||||
func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string
|
||||
func MergeMultiSMap(mps ...map[string]string) map[string]string
|
||||
func MergeL2StrMap(mps ...map[string]map[string]string) map[string]map[string]string
|
||||
@@ -900,16 +964,23 @@ func MakeByKeys(keys []string, val any) (mp map[string]any)
|
||||
func SetByPath(mp *map[string]any, path string, val any) error
|
||||
func SetByKeys(mp *map[string]any, keys []string, val any) (err error)
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Math/Number
|
||||
|
||||
> Package `github.com/gookit/goutil/mathutil`
|
||||
|
||||
Package `mathutil` provide math(int, number) util functions. eg: convert, math calc, random
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at mathutil/calc.go
|
||||
func Abs[T comdef.Int](val T) T
|
||||
// source at mathutil/check.go
|
||||
func IsNumeric(c byte) bool
|
||||
func IsInteger(val any) 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
|
||||
@@ -928,11 +999,7 @@ 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 NewConvOption[T any](optFns ...ConvOptionFn[T]) *ConvOption[T]
|
||||
func WithNilAsFail[T any](opt *ConvOption[T])
|
||||
func WithHandlePtr[T any](opt *ConvOption[T])
|
||||
func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T]
|
||||
// source at mathutil/conv2int.go
|
||||
func Int(in any) (int, error)
|
||||
func SafeInt(in any) int
|
||||
func QuietInt(in any) int
|
||||
@@ -943,8 +1010,6 @@ func IntOr(in any, defVal int) int
|
||||
func IntOrErr(in any) (int, error)
|
||||
func ToInt(in any) (int, error)
|
||||
func ToIntWith(in any, optFns ...ConvOptionFn[int]) (iVal int, err error)
|
||||
func StrInt(s string) int
|
||||
func StrIntOr(s string, defVal int) int
|
||||
func Int64(in any) (int64, error)
|
||||
func SafeInt64(in any) int64
|
||||
func QuietInt64(in any) int64
|
||||
@@ -972,6 +1037,19 @@ func Uint64Or(in any, defVal uint64) uint64
|
||||
func Uint64OrErr(in any) (uint64, error)
|
||||
func ToUint64(in any) (uint64, error)
|
||||
func ToUint64With(in any, optFns ...ConvOptionFn[uint64]) (u64 uint64, err error)
|
||||
func StrInt(s string) int
|
||||
func StrIntOr(s string, defVal int) int
|
||||
func TryStrInt(s string) (int, error)
|
||||
func TryStrInt64(s string) (int64, error)
|
||||
func TryStrUint64(s string) (uint64, error)
|
||||
// source at mathutil/convert.go
|
||||
func NewConvOption[T any](optFns ...ConvOptionFn[T]) *ConvOption[T]
|
||||
func WithNilAsFail[T any](opt *ConvOption[T])
|
||||
func WithHandlePtr[T any](opt *ConvOption[T])
|
||||
func WithStrictMode[T any](opt *ConvOption[T])
|
||||
func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T]
|
||||
func StrictInt(val any) (int64, bool)
|
||||
func StrictUint(val any) (uint64, bool)
|
||||
func QuietFloat(in any) float64
|
||||
func SafeFloat(in any) float64
|
||||
func FloatOrPanic(in any) float64
|
||||
@@ -995,6 +1073,7 @@ func TryToString(val any, defaultAsErr bool) (string, error)
|
||||
func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error)
|
||||
// source at mathutil/format.go
|
||||
func DataSize(size uint64) string
|
||||
func FormatBytes(bytes int) string
|
||||
func HowLongAgo(sec int64) string
|
||||
// source at mathutil/mathutil.go
|
||||
func OrElse[T comdef.Number](val, defVal T) T
|
||||
@@ -1015,11 +1094,17 @@ func RandInt(min, max int) int
|
||||
func RandIntWithSeed(min, max int, seed int64) int
|
||||
func RandomIntWithSeed(min, max int, seed int64) int
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Reflects
|
||||
|
||||
> Package `github.com/gookit/goutil/reflects`
|
||||
|
||||
Package `reflects` Provide extends reflection util functions. eg: check, convert, value set, etc.
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at reflects/check.go
|
||||
func IsTimeType(t reflect.Type) bool
|
||||
@@ -1085,11 +1170,17 @@ func SetRValue(rv, val reflect.Value)
|
||||
func Wrap(rv reflect.Value) Value
|
||||
func ValueOf(v any) Value
|
||||
```
|
||||
</details>
|
||||
|
||||
### Structs
|
||||
|
||||
### Struct Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/structs`
|
||||
|
||||
Package `structs` Provide some extends util functions for struct. eg: tag parse, struct init, value set/get
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at structs/alias.go
|
||||
func NewAliases(checker func(alias string)) *Aliases
|
||||
@@ -1140,11 +1231,15 @@ func WithBeforeSetFn(fn BeforeSetFunc) SetOptFunc
|
||||
func BindData(ptr any, data map[string]any, optFns ...SetOptFunc) error
|
||||
func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error
|
||||
```
|
||||
</details>
|
||||
|
||||
### Strings
|
||||
|
||||
### String Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/strutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at strutil/bytes.go
|
||||
func NewBuffer(initSize ...int) *Buffer
|
||||
@@ -1152,16 +1247,21 @@ func NewByteChanPool(maxSize, width, capWidth int) *ByteChanPool
|
||||
// source at strutil/check.go
|
||||
func IsNumChar(c byte) bool
|
||||
func IsInt(s string) bool
|
||||
func IsUint(s string) bool
|
||||
func IsFloat(s string) bool
|
||||
func IsNumeric(s string) bool
|
||||
func IsPositiveNum(s string) bool
|
||||
func IsAlphabet(char uint8) bool
|
||||
func IsAlphaNum(c uint8) bool
|
||||
func IsUpper(s string) bool
|
||||
func IsLower(s string) 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 ContainsByteOne(s string, bs []byte) bool
|
||||
func ContainsOne(s string, subs []string) bool
|
||||
func HasOneSub(s string, subs []string) bool
|
||||
func IContainsOne(s string, subs []string) bool
|
||||
@@ -1186,6 +1286,7 @@ func HasEmpty(ss ...string) bool
|
||||
func IsAllEmpty(ss ...string) bool
|
||||
func IsVersion(s string) bool
|
||||
func IsVarName(s string) bool
|
||||
func IsEnvName(s string) bool
|
||||
func Compare(s1, s2, op string) bool
|
||||
func VersionCompare(v1, v2, op string) bool
|
||||
func SimpleMatch(s string, keywords []string) bool
|
||||
@@ -1197,7 +1298,9 @@ 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 BaseConvInt(src uint64, to int) string
|
||||
func BaseConvByTpl(src string, fromBase, toBase string) string
|
||||
func BaseConvIntByTpl(dec uint64, toBase string) string
|
||||
// source at strutil/convert.go
|
||||
func Quote(s string) string
|
||||
func Unquote(s string) string
|
||||
@@ -1257,7 +1360,6 @@ 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
|
||||
@@ -1299,6 +1401,10 @@ 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
|
||||
func Replaces(str string, pairs map[string]string) string
|
||||
func ReplaceVars(s string, vars map[string]string) string
|
||||
func NewReplacer(pairs map[string]string) *strings.Replacer
|
||||
func WrapTag(s, tag string) string
|
||||
// source at strutil/gensn.go
|
||||
func MicroTimeID() string
|
||||
func MicroTimeHexID() string
|
||||
@@ -1307,7 +1413,8 @@ func MTimeBase36() string
|
||||
func MTimeBaseID(toBase int) string
|
||||
func DatetimeNo(prefix string) string
|
||||
func DateSN(prefix string) string
|
||||
func DateSNV2(prefix string, extBase ...int) string
|
||||
func DateSNv2(prefix string, extBase ...int) string
|
||||
func DateSNv3(prefix string, dateLen int, extBase ...int) string
|
||||
// source at strutil/hash.go
|
||||
func Md5(src any) string
|
||||
func MD5(src any) string
|
||||
@@ -1335,6 +1442,7 @@ 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 NumVersion(s string) string
|
||||
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)
|
||||
@@ -1398,31 +1506,17 @@ func OrElse(s, orVal string) string
|
||||
func OrElseNilSafe(s *string, 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 WrapTag(s, tag string) string
|
||||
func SubstrCount(s, substr string, params ...uint64) (int, error)
|
||||
```
|
||||
</details>
|
||||
|
||||
### Syncs
|
||||
|
||||
> Package `github.com/gookit/goutil/syncs`
|
||||
|
||||
```go
|
||||
// source at syncs/chan.go
|
||||
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 WaitCloseSignals(onClose func(sig os.Signal), sigCh ...chan os.Signal)
|
||||
func SignalHandler(ctx context.Context, signals ...os.Signal) (execute func() error, interrupt func(error))
|
||||
```
|
||||
|
||||
### System Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/sysutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at sysutil/exec.go
|
||||
func NewCmd(bin string, args ...string) *cmdr.Cmd
|
||||
@@ -1473,6 +1567,13 @@ func OpenURL(URL string) error
|
||||
// source at sysutil/sysutil_nonwin.go
|
||||
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
|
||||
// source at sysutil/user.go
|
||||
func MustFindUser(uname string) *user.User
|
||||
func LoginUser() *user.User
|
||||
@@ -1491,24 +1592,29 @@ func ChangeUserByName(newUname string) error
|
||||
func ChangeUserUidGid(newUID int, newGid int) error
|
||||
func ChangeUserUIDGid(newUID int, newGid int) (err error)
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Testing Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/testutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at testutil/buffer.go
|
||||
func NewBuffer() *byteutil.Buffer
|
||||
func NewSafeBuffer() *SafeBuffer
|
||||
// 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 SetOsEnvs(mp map[string]string) string
|
||||
func RemoveTmpEnvs(tmpKey string)
|
||||
func ClearOSEnv()
|
||||
func RevertOSEnv()
|
||||
func RunOnCleanEnv(runFn func())
|
||||
func MockOsEnv(mp map[string]string, fn func())
|
||||
func MockCleanOsEnv(mp map[string]string, fn func())
|
||||
// source at testutil/httpmock.go
|
||||
func NewHTTPRequest(method, path string, data *MD) *http.Request
|
||||
@@ -1533,12 +1639,17 @@ func RestoreTimeLocal()
|
||||
func NewTestWriter() *TestWriter
|
||||
func NewDirEnt(fPath string, isDir ...bool) *fakeobj.DirEntry
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Timex
|
||||
|
||||
> Package `github.com/gookit/goutil/timex`
|
||||
|
||||
Provides an enhanced time.Time implementation, and add more commonly used functional methods.
|
||||
Provides an enhanced `time.Time` implementation, and add more commonly used functional methods.
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at timex/check.go
|
||||
func IsDuration(s string) bool
|
||||
@@ -1546,12 +1657,14 @@ 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 FormatDuration(d time.Duration) 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 ParseDuration(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)
|
||||
@@ -1600,6 +1713,8 @@ func FormatUnix(sec int64, layout ...string) string
|
||||
func FormatUnixBy(sec int64, layout string) string
|
||||
func FormatUnixByTpl(sec int64, template ...string) string
|
||||
```
|
||||
</details>
|
||||
|
||||
#### Timex Usage
|
||||
|
||||
**Create timex instance**
|
||||
@@ -1719,6 +1834,7 @@ date := FormatUnixByTpl(ts, "Y-m-d H:I:S") // Get: 2022-04-20 19:40:34
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Code Check & Testing
|
||||
|
||||
```bash
|
||||
|
||||
230
vendor/github.com/gookit/goutil/README.zh-CN.md
generated
vendored
230
vendor/github.com/gookit/goutil/README.zh-CN.md
generated
vendored
@@ -1,4 +1,4 @@
|
||||
# Go Util
|
||||
# GoUtil
|
||||
|
||||

|
||||
[](https://github.com/gookit/goutil)
|
||||
@@ -7,7 +7,7 @@
|
||||
[](https://coveralls.io/github/gookit/goutil?branch=master)
|
||||
[](https://pkg.go.dev/github.com/gookit/goutil)
|
||||
|
||||
`goutil` Go 常用功能的扩展工具库(**800+**)。包含:数字,byte, 字符串,slice/数组,Map,结构体,反射,文本,文件,错误,时间日期,测试,特殊处理,格式化,常用信息获取等等。
|
||||
`goutil` Go 常用功能的扩展工具库(**900+**)。包含:数字,byte, 字符串,slice/数组,Map,结构体,反射,文本,文件,错误,时间日期,测试,特殊处理,格式化,常用信息获取等等。
|
||||
|
||||
> **[EN README](README.md)**
|
||||
|
||||
@@ -53,17 +53,17 @@
|
||||
- [`cmdline`](cliutil/cmdline) 提供 cmdline 解析,args 构建到 cmdline
|
||||
- [`encodes`](x/encodes): Provide some encoding/decoding, hash, crypto util functions. eg: base64, hex, etc.
|
||||
- [`finder`](x/finder) 提供简单方便的file/dir查找功能,支持过滤、排除、匹配、忽略等。
|
||||
- [textscan](strutil/textscan) 实现了一个快速扫描和分析文本内容的解析器. 可用于解析 INI, Properties 等格式内容
|
||||
- [textutil](strutil/textutil) 提供一些常用的扩展文本处理功能函数。
|
||||
- [cmdr](sysutil/cmdr) 提供快速构建和运行一个cmd,批量运行多个cmd任务
|
||||
- [process](sysutil/process) 提供一些进程操作相关的实用功能。
|
||||
- [`textscan`](strutil/textscan) 实现了一个快速扫描和分析文本内容的解析器. 可用于解析 INI, Properties 等格式内容
|
||||
- [`textutil`](strutil/textutil) 提供一些常用的扩展文本处理功能函数。
|
||||
- [`cmdr`](sysutil/cmdr) 提供快速构建和运行一个cmd,批量运行多个cmd任务
|
||||
- [`process`](sysutil/process) 提供一些进程操作相关的实用功能。
|
||||
- [`fmtutil`](x/fmtutil) 格式化数据工具函数 eg:数据size
|
||||
- [`goinfo`](x/goinfo) 提供一些与Go info, runtime 相关的工具函数。
|
||||
|
||||
## GoDoc
|
||||
|
||||
- [Godoc for github](https://pkg.go.dev/github.com/gookit/goutil)
|
||||
- Wiki docs on [DeepWiki - gookit/goutil](https://deepwiki.com/gookit/goutil)
|
||||
- Wiki docs on [ZRead.ai - gookit/goutil](https://zread.ai/gookit/goutil)
|
||||
|
||||
## 获取
|
||||
|
||||
@@ -109,6 +109,8 @@ dump.Print(somevar, somevar2, ...)
|
||||
|
||||
> Package `github.com/gookit/goutil/arrutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at arrutil/arrutil.go
|
||||
func GetRandomOne[T any](arr []T) T
|
||||
@@ -152,6 +154,7 @@ 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 ToMap[T any, K comdef.ScalarType, V any](list []T, mapFn func(T) (K, V)) map[K]V
|
||||
func AnyToSlice(sl any) (ls []any, err error)
|
||||
func AnyToStrings(arr any) []string
|
||||
func MustToStrings(arr any) []string
|
||||
@@ -171,7 +174,8 @@ func FormatIndent(arr any, indent string) string
|
||||
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 Map[T, V any](list []T, mapFn MapFn[T, V]) []V
|
||||
func Map1[T, R any](list []T, fn func(t T) R) []R
|
||||
func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V
|
||||
func Unique[T comdef.NumberOrString](list []T) []T
|
||||
func IndexOf[T comdef.NumberOrString](val T, list []T) int
|
||||
@@ -189,6 +193,8 @@ 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
|
||||
```
|
||||
</details>
|
||||
|
||||
#### ArrUtil Usage
|
||||
|
||||
**check value**:
|
||||
@@ -211,10 +217,13 @@ ss, err := arrutil.ToStrings([]int{1, 2}) // ss: []string{"1", "2"}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Bytes Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/byteutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at byteutil/buffer.go
|
||||
func NewBuffer() *Buffer
|
||||
@@ -244,18 +253,22 @@ func NewStdEncoder(encFn BytesEncodeFunc, decFn BytesDecodeFunc) *StdEncoder
|
||||
// source at byteutil/pool.go
|
||||
func NewChanPool(chSize int, width int, capWidth int) *ChanPool
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Cflag
|
||||
|
||||
> Package `github.com/gookit/goutil/cflag`
|
||||
|
||||
`cflag` - Wraps and extends go `flag.FlagSet` to build simple command line applications
|
||||
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at cflag/app.go
|
||||
func NewApp(fns ...func(app *App)) *App
|
||||
func NewCmd(name, desc string, runFunc ...func(c *Cmd) error) *Cmd
|
||||
// source at cflag/cflag.go
|
||||
func SetDebug(open bool)
|
||||
func New(fns ...func(c *CFlags)) *CFlags
|
||||
func NewWith(name, version, desc string, 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)
|
||||
@@ -269,6 +282,8 @@ func Value
|
||||
// source at cflag/optarg.go
|
||||
func NewArg(name, desc string, required bool) *FlagArg
|
||||
// source at cflag/util.go
|
||||
func SetDebug(open bool)
|
||||
func DebugMsg(format string, args ...any)
|
||||
func IsGoodName(name string) bool
|
||||
func IsZeroValue(opt *flag.Flag, value string) (bool, bool)
|
||||
func AddPrefix(name string) string
|
||||
@@ -280,15 +295,20 @@ func IsFlagHelpErr(err error) bool
|
||||
func WrapColorForCode(s string) string
|
||||
func ReplaceShorts(args []string, shortsMap map[string]string) []string
|
||||
```
|
||||
</details>
|
||||
|
||||
#### `cflag` Usage
|
||||
|
||||
`cflag` 使用说明请看 [cflag/README.zh-CN.md](cflag/README.zh-CN.md)
|
||||
`cflag` usage please see [cflag/README.md](cflag/README.md)
|
||||
|
||||
|
||||
|
||||
### CLI Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/cliutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at cliutil/cliutil.go
|
||||
func SplitMulti(ss []string, sep string) []string
|
||||
@@ -325,6 +345,8 @@ func InputIsYes(ans string) bool
|
||||
func ByteIsYes(ans byte) bool
|
||||
func ReadPassword(question ...string) string
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
#### CLI Util Usage
|
||||
|
||||
@@ -381,10 +403,13 @@ Build line: ./myapp -a val0 -m "this is message" arg0
|
||||
|
||||
> More, please see [./cliutil/README](cliutil/README.md)
|
||||
|
||||
|
||||
### Var Dumper
|
||||
|
||||
> Package `github.com/gookit/goutil/dump`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at dump/dump.go
|
||||
func Std() *Dumper
|
||||
@@ -411,7 +436,10 @@ func WithoutPosition() OptionFunc
|
||||
func WithoutOutput(out io.Writer) OptionFunc
|
||||
func WithoutColor() OptionFunc
|
||||
func WithoutType() OptionFunc
|
||||
func WithoutLen() OptionFunc
|
||||
```
|
||||
</details>
|
||||
|
||||
#### Examples
|
||||
|
||||
example code:
|
||||
@@ -456,10 +484,13 @@ Preview:
|
||||

|
||||
|
||||
|
||||
|
||||
### ENV/Environment
|
||||
|
||||
> Package `github.com/gookit/goutil/envutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at envutil/envutil.go
|
||||
func VarReplace(s string) string
|
||||
@@ -503,6 +534,8 @@ func UnsetEnvs(keys ...string)
|
||||
func LoadText(text string)
|
||||
func LoadString(line string) bool
|
||||
```
|
||||
</details>
|
||||
|
||||
#### ENV Util Usage
|
||||
|
||||
**helper functions:**
|
||||
@@ -522,15 +555,18 @@ envutil.ParseValue("${ENV_NAME | defValue}")
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Errorx
|
||||
|
||||
> Package `github.com/gookit/goutil/errorx`
|
||||
|
||||
`errorx` 提供了增强的错误报告实现,包含调用堆栈信息并且可以包装上一级错误。
|
||||
`errorx` provides an enhanced error reporting implementation that contains call stack information and can wrap the previous level of error.
|
||||
|
||||
> 在打印 error 时会额外附带调用栈信息, 方便记录日志和查找问题。
|
||||
> Additional call stack information is included when printing errors, making it easy to log and find problems.
|
||||
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at errorx/assert.go
|
||||
func IsTrue(result bool, fmtAndArgs ...any) error
|
||||
@@ -580,12 +616,14 @@ func Is(err, target error) bool
|
||||
func To(err error, target any) bool
|
||||
func As(err error, target any) bool
|
||||
```
|
||||
</details>
|
||||
|
||||
#### Errorx 使用示例
|
||||
|
||||
**创建错误带有调用栈信息**
|
||||
#### Errorx Usage
|
||||
|
||||
- 使用 `errorx.New` 替代 `errors.New`
|
||||
**Create error with call stack info**
|
||||
|
||||
- use the `errorx.New` instead `errors.New`
|
||||
|
||||
```go
|
||||
func doSomething() error {
|
||||
@@ -596,7 +634,7 @@ func doSomething() error {
|
||||
}
|
||||
```
|
||||
|
||||
- 使用 `errorx.Newf` 或者 `errorx.Errorf` 替代 `fmt.Errorf`
|
||||
- use the `errorx.Newf` or `errorx.Errorf` instead `fmt.Errorf`
|
||||
|
||||
```go
|
||||
func doSomething() error {
|
||||
@@ -607,9 +645,9 @@ func doSomething() error {
|
||||
}
|
||||
```
|
||||
|
||||
**包装上一级错误**
|
||||
**Wrap the previous error**
|
||||
|
||||
之前这样使用:
|
||||
used like this before:
|
||||
|
||||
```go
|
||||
if err := SomeFunc(); err != nil {
|
||||
@@ -617,7 +655,7 @@ func doSomething() error {
|
||||
}
|
||||
```
|
||||
|
||||
可以替换成:
|
||||
can be replaced with:
|
||||
|
||||
```go
|
||||
if err := SomeFunc(); err != nil {
|
||||
@@ -625,9 +663,9 @@ func doSomething() error {
|
||||
}
|
||||
```
|
||||
|
||||
**使用效果示例**
|
||||
**Print the errorx.New() error**
|
||||
|
||||
更多关于 `errorx` 的使用请看 [./errorx/README](errorx/README.md)
|
||||
Examples for use `errorx` package, more please see [./errorx/README](errorx/README.md)
|
||||
|
||||
```go
|
||||
err := errorx.New("the error message")
|
||||
@@ -657,16 +695,23 @@ runtime.goexit()
|
||||
```
|
||||
|
||||
|
||||
|
||||
### File System
|
||||
|
||||
> Package `github.com/gookit/goutil/fsutil`
|
||||
|
||||
Package `fsutil` Filesystem util functions: quick check, create, read and write file. eg: file and dir check, operate
|
||||
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```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 IsSymlink(path string) bool
|
||||
func IsAbsPath(aPath string) bool
|
||||
func IsEmptyDir(dirPath string) bool
|
||||
func IsImageFile(path string) bool
|
||||
@@ -682,6 +727,10 @@ 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 FindAllInParentDirs(dirPath, name string, optFns ...FindParentOptFn) []string
|
||||
func FindOneInParentDirs(dirPath, name string, optFns ...FindParentOptFn) string
|
||||
func FindNameInParentDirs(dirPath, name string, collectFn func(fullPath string), optFns ...FindParentOptFn)
|
||||
func FindInParentDirs(dirPath string, matchFunc func(dir string) bool, maxLevel int)
|
||||
func SearchNameUp(dirPath, name string) string
|
||||
func SearchNameUpx(dirPath, name string) (string, bool)
|
||||
func WalkDir(dir string, fn fs.WalkDirFunc) error
|
||||
@@ -715,9 +764,12 @@ func FileExt(fPath string) string
|
||||
func Extname(fPath string) string
|
||||
func Suffix(fPath string) string
|
||||
func Expand(pathStr string) string
|
||||
func ExpandHome(pathStr string) string
|
||||
func ExpandPath(pathStr string) string
|
||||
func ResolvePath(pathStr string) string
|
||||
func SplitPath(pathStr string) (dir, name string)
|
||||
func UserHomeDir() string
|
||||
func HomeDir() string
|
||||
// source at fsutil/info_nonwin.go
|
||||
func Realpath(pathStr string) string
|
||||
// source at fsutil/mime.go
|
||||
@@ -725,9 +777,11 @@ 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 Mkdir(dirPath string, perm fs.FileMode) error
|
||||
func MkdirQuick(dirPath string) error
|
||||
func EnsureDir(path string) error
|
||||
func MkDirs(perm fs.FileMode, dirPaths ...string) error
|
||||
func MkSubDirs(perm fs.FileMode, parentDir string, subDirs ...string) error
|
||||
func MkParentDir(fpath string) error
|
||||
func NewOpenOption(optFns ...OpenOptionFunc) *OpenOption
|
||||
func OpenOptOrNew(opt *OpenOption) *OpenOption
|
||||
@@ -781,7 +835,10 @@ 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
|
||||
func CreateSymlink(target, linkPath string) error
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
#### FsUtil Usage
|
||||
|
||||
@@ -813,6 +870,7 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
### JSON Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/jsonutil`
|
||||
@@ -843,10 +901,13 @@ func IsObject(s string) bool
|
||||
func StripComments(src string) string
|
||||
```
|
||||
|
||||
### Map
|
||||
|
||||
### Maputil
|
||||
|
||||
> Package `github.com/gookit/goutil/maputil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at maputil/check.go
|
||||
func HasKey(mp, key any) (ok bool)
|
||||
@@ -892,6 +953,7 @@ func Merge1level(mps ...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 MergeStrMap(src, dst map[string]string) map[string]string
|
||||
func AppendSMap(dst, src map[string]string) map[string]string
|
||||
func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string
|
||||
func MergeMultiSMap(mps ...map[string]string) map[string]string
|
||||
func MergeL2StrMap(mps ...map[string]map[string]string) map[string]map[string]string
|
||||
@@ -902,16 +964,23 @@ func MakeByKeys(keys []string, val any) (mp map[string]any)
|
||||
func SetByPath(mp *map[string]any, path string, val any) error
|
||||
func SetByKeys(mp *map[string]any, keys []string, val any) (err error)
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Math/Number
|
||||
|
||||
> Package `github.com/gookit/goutil/mathutil`
|
||||
|
||||
Package `mathutil` provide math(int, number) util functions. eg: convert, math calc, random
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at mathutil/calc.go
|
||||
func Abs[T comdef.Int](val T) T
|
||||
// source at mathutil/check.go
|
||||
func IsNumeric(c byte) bool
|
||||
func IsInteger(val any) 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
|
||||
@@ -930,11 +999,7 @@ 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 NewConvOption[T any](optFns ...ConvOptionFn[T]) *ConvOption[T]
|
||||
func WithNilAsFail[T any](opt *ConvOption[T])
|
||||
func WithHandlePtr[T any](opt *ConvOption[T])
|
||||
func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T]
|
||||
// source at mathutil/conv2int.go
|
||||
func Int(in any) (int, error)
|
||||
func SafeInt(in any) int
|
||||
func QuietInt(in any) int
|
||||
@@ -945,8 +1010,6 @@ func IntOr(in any, defVal int) int
|
||||
func IntOrErr(in any) (int, error)
|
||||
func ToInt(in any) (int, error)
|
||||
func ToIntWith(in any, optFns ...ConvOptionFn[int]) (iVal int, err error)
|
||||
func StrInt(s string) int
|
||||
func StrIntOr(s string, defVal int) int
|
||||
func Int64(in any) (int64, error)
|
||||
func SafeInt64(in any) int64
|
||||
func QuietInt64(in any) int64
|
||||
@@ -974,6 +1037,19 @@ func Uint64Or(in any, defVal uint64) uint64
|
||||
func Uint64OrErr(in any) (uint64, error)
|
||||
func ToUint64(in any) (uint64, error)
|
||||
func ToUint64With(in any, optFns ...ConvOptionFn[uint64]) (u64 uint64, err error)
|
||||
func StrInt(s string) int
|
||||
func StrIntOr(s string, defVal int) int
|
||||
func TryStrInt(s string) (int, error)
|
||||
func TryStrInt64(s string) (int64, error)
|
||||
func TryStrUint64(s string) (uint64, error)
|
||||
// source at mathutil/convert.go
|
||||
func NewConvOption[T any](optFns ...ConvOptionFn[T]) *ConvOption[T]
|
||||
func WithNilAsFail[T any](opt *ConvOption[T])
|
||||
func WithHandlePtr[T any](opt *ConvOption[T])
|
||||
func WithStrictMode[T any](opt *ConvOption[T])
|
||||
func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T]
|
||||
func StrictInt(val any) (int64, bool)
|
||||
func StrictUint(val any) (uint64, bool)
|
||||
func QuietFloat(in any) float64
|
||||
func SafeFloat(in any) float64
|
||||
func FloatOrPanic(in any) float64
|
||||
@@ -997,6 +1073,7 @@ func TryToString(val any, defaultAsErr bool) (string, error)
|
||||
func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error)
|
||||
// source at mathutil/format.go
|
||||
func DataSize(size uint64) string
|
||||
func FormatBytes(bytes int) string
|
||||
func HowLongAgo(sec int64) string
|
||||
// source at mathutil/mathutil.go
|
||||
func OrElse[T comdef.Number](val, defVal T) T
|
||||
@@ -1017,11 +1094,17 @@ func RandInt(min, max int) int
|
||||
func RandIntWithSeed(min, max int, seed int64) int
|
||||
func RandomIntWithSeed(min, max int, seed int64) int
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Reflects
|
||||
|
||||
> Package `github.com/gookit/goutil/reflects`
|
||||
|
||||
Package `reflects` Provide extends reflection util functions. eg: check, convert, value set, etc.
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at reflects/check.go
|
||||
func IsTimeType(t reflect.Type) bool
|
||||
@@ -1087,11 +1170,17 @@ func SetRValue(rv, val reflect.Value)
|
||||
func Wrap(rv reflect.Value) Value
|
||||
func ValueOf(v any) Value
|
||||
```
|
||||
</details>
|
||||
|
||||
### Structs
|
||||
|
||||
### Struct Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/structs`
|
||||
|
||||
Package `structs` Provide some extends util functions for struct. eg: tag parse, struct init, value set/get
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at structs/alias.go
|
||||
func NewAliases(checker func(alias string)) *Aliases
|
||||
@@ -1142,11 +1231,15 @@ func WithBeforeSetFn(fn BeforeSetFunc) SetOptFunc
|
||||
func BindData(ptr any, data map[string]any, optFns ...SetOptFunc) error
|
||||
func SetValues(ptr any, data map[string]any, optFns ...SetOptFunc) error
|
||||
```
|
||||
</details>
|
||||
|
||||
### Strings
|
||||
|
||||
### String Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/strutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at strutil/bytes.go
|
||||
func NewBuffer(initSize ...int) *Buffer
|
||||
@@ -1154,16 +1247,21 @@ func NewByteChanPool(maxSize, width, capWidth int) *ByteChanPool
|
||||
// source at strutil/check.go
|
||||
func IsNumChar(c byte) bool
|
||||
func IsInt(s string) bool
|
||||
func IsUint(s string) bool
|
||||
func IsFloat(s string) bool
|
||||
func IsNumeric(s string) bool
|
||||
func IsPositiveNum(s string) bool
|
||||
func IsAlphabet(char uint8) bool
|
||||
func IsAlphaNum(c uint8) bool
|
||||
func IsUpper(s string) bool
|
||||
func IsLower(s string) 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 ContainsByteOne(s string, bs []byte) bool
|
||||
func ContainsOne(s string, subs []string) bool
|
||||
func HasOneSub(s string, subs []string) bool
|
||||
func IContainsOne(s string, subs []string) bool
|
||||
@@ -1188,6 +1286,7 @@ func HasEmpty(ss ...string) bool
|
||||
func IsAllEmpty(ss ...string) bool
|
||||
func IsVersion(s string) bool
|
||||
func IsVarName(s string) bool
|
||||
func IsEnvName(s string) bool
|
||||
func Compare(s1, s2, op string) bool
|
||||
func VersionCompare(v1, v2, op string) bool
|
||||
func SimpleMatch(s string, keywords []string) bool
|
||||
@@ -1199,7 +1298,9 @@ 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 BaseConvInt(src uint64, to int) string
|
||||
func BaseConvByTpl(src string, fromBase, toBase string) string
|
||||
func BaseConvIntByTpl(dec uint64, toBase string) string
|
||||
// source at strutil/convert.go
|
||||
func Quote(s string) string
|
||||
func Unquote(s string) string
|
||||
@@ -1259,7 +1360,6 @@ 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
|
||||
@@ -1301,6 +1401,10 @@ 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
|
||||
func Replaces(str string, pairs map[string]string) string
|
||||
func ReplaceVars(s string, vars map[string]string) string
|
||||
func NewReplacer(pairs map[string]string) *strings.Replacer
|
||||
func WrapTag(s, tag string) string
|
||||
// source at strutil/gensn.go
|
||||
func MicroTimeID() string
|
||||
func MicroTimeHexID() string
|
||||
@@ -1309,7 +1413,8 @@ func MTimeBase36() string
|
||||
func MTimeBaseID(toBase int) string
|
||||
func DatetimeNo(prefix string) string
|
||||
func DateSN(prefix string) string
|
||||
func DateSNV2(prefix string, extBase ...int) string
|
||||
func DateSNv2(prefix string, extBase ...int) string
|
||||
func DateSNv3(prefix string, dateLen int, extBase ...int) string
|
||||
// source at strutil/hash.go
|
||||
func Md5(src any) string
|
||||
func MD5(src any) string
|
||||
@@ -1337,6 +1442,7 @@ 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 NumVersion(s string) string
|
||||
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)
|
||||
@@ -1400,31 +1506,17 @@ func OrElse(s, orVal string) string
|
||||
func OrElseNilSafe(s *string, 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 WrapTag(s, tag string) string
|
||||
func SubstrCount(s, substr string, params ...uint64) (int, error)
|
||||
```
|
||||
</details>
|
||||
|
||||
### Syncs
|
||||
|
||||
> Package `github.com/gookit/goutil/syncs`
|
||||
|
||||
```go
|
||||
// source at syncs/chan.go
|
||||
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 WaitCloseSignals(onClose func(sig os.Signal), sigCh ...chan os.Signal)
|
||||
func SignalHandler(ctx context.Context, signals ...os.Signal) (execute func() error, interrupt func(error))
|
||||
```
|
||||
|
||||
### System Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/sysutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at sysutil/exec.go
|
||||
func NewCmd(bin string, args ...string) *cmdr.Cmd
|
||||
@@ -1475,6 +1567,13 @@ func OpenURL(URL string) error
|
||||
// source at sysutil/sysutil_nonwin.go
|
||||
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
|
||||
// source at sysutil/user.go
|
||||
func MustFindUser(uname string) *user.User
|
||||
func LoginUser() *user.User
|
||||
@@ -1493,24 +1592,29 @@ func ChangeUserByName(newUname string) error
|
||||
func ChangeUserUidGid(newUID int, newGid int) error
|
||||
func ChangeUserUIDGid(newUID int, newGid int) (err error)
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Testing Utils
|
||||
|
||||
> Package `github.com/gookit/goutil/testutil`
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at testutil/buffer.go
|
||||
func NewBuffer() *byteutil.Buffer
|
||||
func NewSafeBuffer() *SafeBuffer
|
||||
// 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 SetOsEnvs(mp map[string]string) string
|
||||
func RemoveTmpEnvs(tmpKey string)
|
||||
func ClearOSEnv()
|
||||
func RevertOSEnv()
|
||||
func RunOnCleanEnv(runFn func())
|
||||
func MockOsEnv(mp map[string]string, fn func())
|
||||
func MockCleanOsEnv(mp map[string]string, fn func())
|
||||
// source at testutil/httpmock.go
|
||||
func NewHTTPRequest(method, path string, data *MD) *http.Request
|
||||
@@ -1535,12 +1639,17 @@ func RestoreTimeLocal()
|
||||
func NewTestWriter() *TestWriter
|
||||
func NewDirEnt(fPath string, isDir ...bool) *fakeobj.DirEntry
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Timex
|
||||
|
||||
> Package `github.com/gookit/goutil/timex`
|
||||
|
||||
Provides an enhanced time.Time implementation, and add more commonly used functional methods.
|
||||
Provides an enhanced `time.Time` implementation, and add more commonly used functional methods.
|
||||
|
||||
<details><summary>Click to see functions 👈</summary>
|
||||
|
||||
```go
|
||||
// source at timex/check.go
|
||||
func IsDuration(s string) bool
|
||||
@@ -1548,12 +1657,14 @@ 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 FormatDuration(d time.Duration) 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 ParseDuration(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)
|
||||
@@ -1602,6 +1713,8 @@ func FormatUnix(sec int64, layout ...string) string
|
||||
func FormatUnixBy(sec int64, layout string) string
|
||||
func FormatUnixByTpl(sec int64, template ...string) string
|
||||
```
|
||||
</details>
|
||||
|
||||
#### Timex Usage
|
||||
|
||||
**Create timex instance**
|
||||
@@ -1721,6 +1834,7 @@ date := FormatUnixByTpl(ts, "Y-m-d H:I:S") // Get: 2022-04-20 19:40:34
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Code Check & Testing
|
||||
|
||||
```bash
|
||||
|
||||
21
vendor/github.com/gookit/goutil/arrutil/convert.go
generated
vendored
21
vendor/github.com/gookit/goutil/arrutil/convert.go
generated
vendored
@@ -125,6 +125,27 @@ func SliceToInt64s(arr []any) []int64 {
|
||||
return i64s
|
||||
}
|
||||
|
||||
// ToMap convert a list to new map.
|
||||
//
|
||||
// Example:
|
||||
// type User struct {
|
||||
// Name string
|
||||
// Age int
|
||||
// }
|
||||
// users := []User{{"Tom", 18}, {"Jack", 20}}
|
||||
// mp := arrutil.ToMap(users, func(u User) (string, int) {
|
||||
// return u.Name, u.Age
|
||||
// })
|
||||
// // mp = map[string]int{"Tom":18, "Jack":20}
|
||||
func ToMap[T any, K comdef.ScalarType, V any](list []T, mapFn func(T) (K, V)) map[K]V {
|
||||
mp := make(map[K]V, len(list))
|
||||
for _, item := range list {
|
||||
k, v := mapFn(item)
|
||||
mp[k] = v
|
||||
}
|
||||
return mp
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert func for any-slice
|
||||
*************************************************************/
|
||||
|
||||
123
vendor/github.com/gookit/goutil/arrutil/process.go
generated
vendored
123
vendor/github.com/gookit/goutil/arrutil/process.go
generated
vendored
@@ -38,6 +38,9 @@ func Filter[T any](ls []T, filter ...comdef.MatchFunc[T]) []T {
|
||||
fn = filter[0]
|
||||
} else {
|
||||
fn = func(el T) bool {
|
||||
// if el == nil { // Filter nil value
|
||||
// return false
|
||||
// }
|
||||
return !reflect.ValueOf(el).IsZero()
|
||||
}
|
||||
}
|
||||
@@ -51,24 +54,49 @@ func Filter[T any](ls []T, filter ...comdef.MatchFunc[T]) []T {
|
||||
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
|
||||
// Map a list to new list with map filter function.
|
||||
//
|
||||
// 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))
|
||||
func Map[T, V any](list []T, mapFilter func(input T) (target V, ok bool)) []V {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
flatArr := make([]V, 0, len(list))
|
||||
for _, obj := range list {
|
||||
if target, ok := mapFn(obj); ok {
|
||||
if target, ok := mapFilter(obj); ok {
|
||||
flatArr = append(flatArr, target)
|
||||
}
|
||||
}
|
||||
return flatArr
|
||||
}
|
||||
|
||||
// Column alias of Map func
|
||||
// Map1 a list to new list with map function.
|
||||
//
|
||||
// eg: mapping [object0{},object1{},...] to flatten list [object0.someKey, object1.someKey, ...]
|
||||
func Map1[T, R any](list []T, mapFn func(t T) R) []R {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret := make([]R, len(list))
|
||||
for i := range list {
|
||||
ret[i] = mapFn(list[i])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Column collect sub elements from list. alias of Map func
|
||||
//
|
||||
// Example:
|
||||
// list := []map[string]any{
|
||||
// {"id": 1, "name": "one", "age": 23},
|
||||
// {"id": 2, "name": "two", "age": 23},
|
||||
// {"id": 3, "name": "three", "age": 23},
|
||||
// }
|
||||
// names := arrutil.Column(list, func(el map[string]any) string {
|
||||
// return el["name"].(string)
|
||||
// })
|
||||
func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V {
|
||||
return Map(list, mapFn)
|
||||
}
|
||||
@@ -113,3 +141,82 @@ func FirstOr[T any](list []T, defVal ...T) T {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
|
||||
// Chunk split slice to chunks by size.
|
||||
//
|
||||
// eg: [1,2,3,4,5,6,7,8,9,10] -> [[1,2,3,4], [5,6,7,8], [9,10]]
|
||||
func Chunk[T any](list []T, size int) [][]T {
|
||||
if size <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ln := len(list)
|
||||
if ln == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
chunks := make([][]T, 0, ln/size+1)
|
||||
|
||||
for i := 0; i < ln; i += size {
|
||||
end := i + size
|
||||
if end > ln {
|
||||
end = ln
|
||||
}
|
||||
chunks = append(chunks, list[i:end])
|
||||
}
|
||||
|
||||
return chunks
|
||||
}
|
||||
|
||||
// ChunkBy split slice to chunks by size, and with custom chunk function.
|
||||
//
|
||||
// Example:
|
||||
// list := []map[string]any{
|
||||
// {"id": 1, "name": "one", "age": 23},
|
||||
// {"id": 2, "name": "two", "age": 23},
|
||||
// {"id": 3, "name": "three", "age": 23},
|
||||
// }
|
||||
// chunks := arrutil.ChunkBy(list, 2, func(el map[string]any) map[string]any {
|
||||
// return map[string]any{
|
||||
// "id": el["id"],
|
||||
// "name": el["name"],
|
||||
// }
|
||||
// })
|
||||
// Output: [
|
||||
// [{"id": 1, "name": "one"}, {"id": 2, "name": "two"}],
|
||||
// [{"id": 3, "name": "three"}]
|
||||
// ]
|
||||
func ChunkBy[T, R any](list []T, size int, mapFn func(el T) R) [][]R {
|
||||
if size <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ln := len(list)
|
||||
if ln == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 计算需要的块数量
|
||||
numChunks := ln/size + 1
|
||||
if ln%size == 0 {
|
||||
numChunks = ln / size
|
||||
}
|
||||
|
||||
chunks := make([][]R, 0, numChunks)
|
||||
|
||||
for i := 0; i < ln; i += size {
|
||||
end := i + size
|
||||
if end > ln {
|
||||
end = ln
|
||||
}
|
||||
|
||||
// 创建当前块的切片
|
||||
currentChunk := make([]R, 0, size)
|
||||
for j := i; j < end; j++ {
|
||||
currentChunk = append(currentChunk, mapFn(list[j]))
|
||||
}
|
||||
chunks = append(chunks, currentChunk)
|
||||
}
|
||||
|
||||
return chunks
|
||||
}
|
||||
|
||||
27
vendor/github.com/gookit/goutil/byteutil/buffer.go
generated
vendored
27
vendor/github.com/gookit/goutil/byteutil/buffer.go
generated
vendored
@@ -16,9 +16,7 @@ type Buffer struct {
|
||||
}
|
||||
|
||||
// NewBuffer instance
|
||||
func NewBuffer() *Buffer {
|
||||
return &Buffer{}
|
||||
}
|
||||
func NewBuffer() *Buffer { return &Buffer{} }
|
||||
|
||||
// PrintByte to buffer, ignore error. alias of WriteByte()
|
||||
func (b *Buffer) PrintByte(c byte) {
|
||||
@@ -26,14 +24,10 @@ func (b *Buffer) PrintByte(c byte) {
|
||||
}
|
||||
|
||||
// WriteStr1 quiet write one string to buffer
|
||||
func (b *Buffer) WriteStr1(s string) {
|
||||
b.writeStringNl(s, false)
|
||||
}
|
||||
func (b *Buffer) WriteStr1(s string) { b.writeStringNl(s, false) }
|
||||
|
||||
// WriteStr1Nl quiet write one string and end with newline
|
||||
func (b *Buffer) WriteStr1Nl(s string) {
|
||||
b.writeStringNl(s, true)
|
||||
}
|
||||
func (b *Buffer) WriteStr1Nl(s string) { b.writeStringNl(s, true) }
|
||||
|
||||
// writeStringNl quiet write one string and end with newline
|
||||
func (b *Buffer) writeStringNl(s string, nl bool) {
|
||||
@@ -93,6 +87,9 @@ func (b *Buffer) writeAnysWithNl(vs []any, nl bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// Writef write message to buffer, ignore error. alias of Printf()
|
||||
func (b *Buffer) Writef(tpl string, vs ...any) { _, _ = fmt.Fprintf(b, tpl, vs...) }
|
||||
|
||||
// Printf quick write message to buffer, ignore error.
|
||||
func (b *Buffer) Printf(tpl string, vs ...any) { _, _ = fmt.Fprintf(b, tpl, vs...) }
|
||||
|
||||
@@ -112,16 +109,10 @@ func (b *Buffer) ResetAndGet() string {
|
||||
}
|
||||
|
||||
// Close buffer
|
||||
func (b *Buffer) Close() error {
|
||||
return b.CloseErr
|
||||
}
|
||||
func (b *Buffer) Close() error { return b.CloseErr }
|
||||
|
||||
// Flush buffer
|
||||
func (b *Buffer) Flush() error {
|
||||
return b.FlushErr
|
||||
}
|
||||
func (b *Buffer) Flush() error { return b.FlushErr }
|
||||
|
||||
// Sync anf flush buffer
|
||||
func (b *Buffer) Sync() error {
|
||||
return b.SyncErr
|
||||
}
|
||||
func (b *Buffer) Sync() error { return b.SyncErr }
|
||||
|
||||
2
vendor/github.com/gookit/goutil/byteutil/byteutil.go
generated
vendored
2
vendor/github.com/gookit/goutil/byteutil/byteutil.go
generated
vendored
@@ -4,9 +4,9 @@ package byteutil
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
1
vendor/github.com/gookit/goutil/byteutil/check.go
generated
vendored
1
vendor/github.com/gookit/goutil/byteutil/check.go
generated
vendored
@@ -7,4 +7,3 @@ func IsNumChar(c byte) bool { return c >= '0' && c <= '9' }
|
||||
func IsAlphaChar(c byte) bool {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|
||||
}
|
||||
|
||||
|
||||
7
vendor/github.com/gookit/goutil/byteutil/conv.go
generated
vendored
7
vendor/github.com/gookit/goutil/byteutil/conv.go
generated
vendored
@@ -107,3 +107,10 @@ func ToBytesWithFunc(v any, usrFn ToBytesFunc) ([]byte, error) {
|
||||
return usrFn(val)
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse 反转字节数组 eg: ABCD -> DCBA
|
||||
func Reverse(arr []byte) {
|
||||
for i := 0; i < len(arr)/2; i++ {
|
||||
arr[i], arr[len(arr)-1-i] = arr[len(arr)-1-i], arr[i]
|
||||
}
|
||||
}
|
||||
|
||||
16
vendor/github.com/gookit/goutil/comdef/consts.go
generated
vendored
16
vendor/github.com/gookit/goutil/comdef/consts.go
generated
vendored
@@ -1,6 +1,6 @@
|
||||
package comdef
|
||||
|
||||
// consts for compare operation
|
||||
// constants for compare operation
|
||||
const (
|
||||
OpEq = "="
|
||||
OpNeq = "!="
|
||||
@@ -10,7 +10,7 @@ const (
|
||||
OpGte = ">="
|
||||
)
|
||||
|
||||
// consts quote chars
|
||||
// constants quote chars
|
||||
const (
|
||||
SingleQuote = '\''
|
||||
DoubleQuote = '"'
|
||||
@@ -25,3 +25,15 @@ const (
|
||||
const NoIdx = -1
|
||||
|
||||
// const VarPathReg = `(\w[\w-]*(?:\.[\w-]+)*)`
|
||||
|
||||
// Align define align, position: L, C, R, Auto
|
||||
type Align uint8
|
||||
type Position = Align // Position alias of Align
|
||||
|
||||
// constants for align, position: L, C, R, Auto
|
||||
const (
|
||||
Left Align = iota
|
||||
Center
|
||||
Right
|
||||
PosAuto
|
||||
)
|
||||
|
||||
2
vendor/github.com/gookit/goutil/conv.go
generated
vendored
2
vendor/github.com/gookit/goutil/conv.go
generated
vendored
@@ -122,7 +122,7 @@ func ConvOrDefault(val any, kind reflect.Kind, defVal any) any {
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// val, err := ToKind("123", reflect.Int) // 123
|
||||
// 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:
|
||||
|
||||
198
vendor/github.com/gookit/goutil/envutil/dotenv.go
generated
vendored
Normal file
198
vendor/github.com/gookit/goutil/envutil/dotenv.go
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
package envutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
)
|
||||
|
||||
// DefaultEnvFile default file name
|
||||
const DefaultEnvFile = ".env"
|
||||
|
||||
// Dotenv load and parse dotenv files
|
||||
type Dotenv struct {
|
||||
// Files dot env file paths, allow multi files.
|
||||
// - filename support simple glob pattern. eg: ".env.*"
|
||||
//
|
||||
// default: [".env"]
|
||||
Files []string
|
||||
// BaseDir base dir for join files path
|
||||
//
|
||||
// default is workdir
|
||||
BaseDir string
|
||||
// UpperKey change key to upper on set ENV. default: true
|
||||
UpperKey bool
|
||||
// IgnoreNotExist only load exists.
|
||||
//
|
||||
// - default: false - will return error if not exists
|
||||
IgnoreNotExist bool
|
||||
// LoadFirstExist only load first exists env file on Files
|
||||
LoadFirstExist bool
|
||||
|
||||
loadFiles []string
|
||||
loadData map[string]string
|
||||
}
|
||||
|
||||
// NewDotenv create a new dotenv config
|
||||
func NewDotenv() *Dotenv {
|
||||
return &Dotenv{
|
||||
UpperKey: true,
|
||||
Files: []string{DefaultEnvFile},
|
||||
// init fields
|
||||
loadData: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// LoadAndInit load dotenv files and parse to os.Environ
|
||||
func (c *Dotenv) LoadAndInit() error {
|
||||
return c.doLoadFiles(c.Files)
|
||||
}
|
||||
|
||||
// LoadFiles append load dotenv files
|
||||
// - filename support simple glob pattern. eg: ".env.*"
|
||||
func (c *Dotenv) LoadFiles(files ...string) error {
|
||||
return c.doLoadFiles(files)
|
||||
}
|
||||
|
||||
// LoadText load dotenv contents and parse to os Env
|
||||
func (c *Dotenv) LoadText(contents string) error {
|
||||
return c.parseAndSetEnv(contents)
|
||||
}
|
||||
|
||||
// do load dotenv files
|
||||
func (c *Dotenv) doLoadFiles(files []string) error {
|
||||
var filePath string
|
||||
for _, file := range files {
|
||||
filePath = strings.TrimSpace(file)
|
||||
if c.BaseDir != "" && !filepath.IsAbs(file) {
|
||||
filePath = filepath.Join(c.BaseDir, file)
|
||||
}
|
||||
|
||||
// load and parse to ENV
|
||||
if err := c.loadFile(filePath); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.LoadFirstExist && len(c.loadFiles) > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Dotenv) loadFile(filePath string) error {
|
||||
// filename support simple glob pattern.
|
||||
if strings.ContainsRune(filePath, '*') {
|
||||
matches, err := filepath.Glob(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, matchFile := range matches {
|
||||
if err = c.parseFile(matchFile); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Load single file
|
||||
return c.parseFile(filePath)
|
||||
}
|
||||
|
||||
// parseFile load single file and parse to ENV
|
||||
func (c *Dotenv) parseFile(filePath string) error {
|
||||
contents, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
// IgnoreNotExist: skip non-existent files
|
||||
if c.IgnoreNotExist && os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.parseAndSetEnv(string(contents))
|
||||
if err == nil {
|
||||
c.loadFiles = append(c.loadFiles, filePath)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Dotenv) parseAndSetEnv(contents string) error {
|
||||
// Parse ENV lines
|
||||
envMp, err := comfunc.ParseEnvLines(contents, comfunc.ParseEnvLineOption{
|
||||
SkipOnErrorLine: true,
|
||||
})
|
||||
|
||||
// Set to ENV
|
||||
for key, val := range envMp {
|
||||
key = strings.ToUpper(key)
|
||||
c.loadData[key] = val
|
||||
_ = os.Setenv(key, val)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// UnloadEnv remove loaded dotenv data from os.Environ
|
||||
func (c *Dotenv) UnloadEnv() bool {
|
||||
if len(c.loadData) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for key := range c.loadData {
|
||||
_ = os.Unsetenv(key)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// LoadedData get loaded dotenv data map
|
||||
func (c *Dotenv) LoadedData() map[string]string {
|
||||
return c.loadData
|
||||
}
|
||||
|
||||
// LoadedFiles get loaded dotenv files
|
||||
func (c *Dotenv) LoadedFiles() []string {
|
||||
return c.loadFiles
|
||||
}
|
||||
|
||||
// Reset unload all loaded ENV and reset data
|
||||
func (c *Dotenv) Reset() {
|
||||
c.UnloadEnv()
|
||||
c.loadFiles = nil
|
||||
c.loadData = make(map[string]string)
|
||||
}
|
||||
|
||||
//
|
||||
// region standard dotenv instance
|
||||
//
|
||||
|
||||
var stdEnv = NewDotenv()
|
||||
|
||||
// StdDotenv get standard dotenv instance
|
||||
func StdDotenv() *Dotenv { return stdEnv }
|
||||
|
||||
// DotenvLoad load dotenv file and parse to ENV
|
||||
func DotenvLoad(fns ...func(cfg *Dotenv)) error {
|
||||
for _, fn := range fns {
|
||||
fn(stdEnv)
|
||||
}
|
||||
return stdEnv.LoadAndInit()
|
||||
}
|
||||
|
||||
// LoadEnvFiles load dotenv files and parse to ENV
|
||||
func LoadEnvFiles(baseDir string, files ...string) error {
|
||||
return DotenvLoad(func(cfg *Dotenv) {
|
||||
cfg.BaseDir = baseDir
|
||||
if len(files) > 0 {
|
||||
cfg.Files = files
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// LoadedEnvFiles get loaded dotenv files
|
||||
func LoadedEnvFiles() []string {
|
||||
return stdEnv.LoadedFiles()
|
||||
}
|
||||
|
||||
8
vendor/github.com/gookit/goutil/envutil/get.go
generated
vendored
8
vendor/github.com/gookit/goutil/envutil/get.go
generated
vendored
@@ -9,6 +9,12 @@ import (
|
||||
"github.com/gookit/goutil/x/basefn"
|
||||
)
|
||||
|
||||
// HasEnv check ENV key exists
|
||||
func HasEnv(name string) bool {
|
||||
_, ok := os.LookupEnv(name)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Getenv get ENV value by key name, can with default value
|
||||
func Getenv(name string, def ...string) string {
|
||||
val := os.Getenv(name)
|
||||
@@ -68,7 +74,7 @@ func GetMulti(names ...string) map[string]string {
|
||||
return valMap
|
||||
}
|
||||
|
||||
// OnExist check ENV value by key name, if exists call fn
|
||||
// OnExist check ENV value by key name, will call fn on value exists(not-empty)
|
||||
func OnExist(name string, fn func(val string)) bool {
|
||||
if val := os.Getenv(name); val != "" {
|
||||
fn(val)
|
||||
|
||||
1
vendor/github.com/gookit/goutil/envutil/info.go
generated
vendored
1
vendor/github.com/gookit/goutil/envutil/info.go
generated
vendored
@@ -36,7 +36,6 @@ func IsMSys() bool {
|
||||
return sysutil.IsMSys()
|
||||
}
|
||||
|
||||
|
||||
// IsTerminal isatty check
|
||||
//
|
||||
// Usage:
|
||||
|
||||
5
vendor/github.com/gookit/goutil/envutil/set.go
generated
vendored
5
vendor/github.com/gookit/goutil/envutil/set.go
generated
vendored
@@ -34,7 +34,8 @@ func UnsetEnvs(keys ...string) {
|
||||
// LoadText parse multiline text to ENV. Can use to load .env file contents.
|
||||
//
|
||||
// Usage:
|
||||
// envutil.LoadText(fsutil.ReadFile(".env"))
|
||||
//
|
||||
// envutil.LoadText(fsutil.ReadFile(".env"))
|
||||
func LoadText(text string) {
|
||||
envMp := SplitText2map(text)
|
||||
for key, value := range envMp {
|
||||
@@ -42,7 +43,7 @@ func LoadText(text string) {
|
||||
}
|
||||
}
|
||||
|
||||
// LoadString set line to ENV. e.g.: KEY=VALUE
|
||||
// LoadString set line to ENV. e.g.: "KEY=VALUE"
|
||||
func LoadString(line string) bool {
|
||||
k, v := comfunc.SplitLineToKv(line, "=")
|
||||
if len(k) > 0 {
|
||||
|
||||
3
vendor/github.com/gookit/goutil/errorx/errorx.go
generated
vendored
3
vendor/github.com/gookit/goutil/errorx/errorx.go
generated
vendored
@@ -265,7 +265,6 @@ func WithStack(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ErrorX{
|
||||
msg: err.Error(),
|
||||
// prev: err,
|
||||
@@ -278,7 +277,6 @@ func Traced(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ErrorX{
|
||||
msg: err.Error(),
|
||||
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
|
||||
@@ -290,7 +288,6 @@ func Stacked(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ErrorX{
|
||||
msg: err.Error(),
|
||||
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
|
||||
|
||||
11
vendor/github.com/gookit/goutil/fsutil/check.go
generated
vendored
11
vendor/github.com/gookit/goutil/fsutil/check.go
generated
vendored
@@ -61,6 +61,8 @@ func FileExists(path string) bool {
|
||||
}
|
||||
|
||||
// IsFile reports whether the named file or directory exists.
|
||||
//
|
||||
// - NOTE: not support symlink file
|
||||
func IsFile(path string) bool {
|
||||
if path == "" || len(path) > 468 {
|
||||
return false
|
||||
@@ -72,6 +74,15 @@ func IsFile(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsSymlink reports whether the named file is a symlink.
|
||||
func IsSymlink(path string) bool {
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return fi.Mode()&os.ModeSymlink != 0
|
||||
}
|
||||
|
||||
// IsAbsPath is abs path.
|
||||
func IsAbsPath(aPath string) bool {
|
||||
if len(aPath) > 0 {
|
||||
|
||||
113
vendor/github.com/gookit/goutil/fsutil/find.go
generated
vendored
113
vendor/github.com/gookit/goutil/fsutil/find.go
generated
vendored
@@ -23,7 +23,7 @@ func FilePathInDirs(fPath string, dirs ...string) string {
|
||||
}
|
||||
|
||||
for _, dirPath := range dirs {
|
||||
fPath := JoinSubPaths(dirPath, fPath)
|
||||
fPath = JoinSubPaths(dirPath, fPath)
|
||||
if FileExists(fPath) {
|
||||
return fPath
|
||||
}
|
||||
@@ -67,6 +67,103 @@ func MatchFirst(paths []string, matcher PathMatchFunc, defaultPath string) strin
|
||||
return defaultPath
|
||||
}
|
||||
|
||||
// FindParentOption options
|
||||
type FindParentOption struct {
|
||||
MaxLevel int // default: 10
|
||||
// NeedDir true: find dirs; false(default): find files
|
||||
NeedDir bool
|
||||
OnlyOne bool // only find one, default: true
|
||||
// Collector func
|
||||
Collector func(fullPath string)
|
||||
// MatchFunc custom matcher func. return false to stop find.
|
||||
MatchFunc func(currentDir string) bool
|
||||
}
|
||||
|
||||
// FindParentOptFn find parent option func
|
||||
type FindParentOptFn func(opt *FindParentOption)
|
||||
|
||||
// FindAllInParentDirs looks for all match file(default)/dir in the current directory and parent directories
|
||||
func FindAllInParentDirs(dirPath, name string, optFns ...FindParentOptFn) []string {
|
||||
var foundPaths []string
|
||||
optFns = append(optFns, func(opt *FindParentOption) {
|
||||
opt.OnlyOne = false
|
||||
})
|
||||
|
||||
FindNameInParentDirs(dirPath, name, func(fullPath string) {
|
||||
foundPaths = append(foundPaths, fullPath)
|
||||
}, optFns...)
|
||||
return foundPaths
|
||||
}
|
||||
|
||||
// FindOneInParentDirs looks for a file(default)/dir in the current directory and parent directories
|
||||
func FindOneInParentDirs(dirPath, name string, optFns ...FindParentOptFn) string {
|
||||
var foundPath string
|
||||
FindNameInParentDirs(dirPath, name, func(fullPath string) {
|
||||
foundPath = fullPath
|
||||
}, optFns...)
|
||||
return foundPath
|
||||
}
|
||||
|
||||
// FindNameInParentDirs looks for file(default)/dir in the current directory and parent directories
|
||||
func FindNameInParentDirs(dirPath, name string, collectFn func(fullPath string), optFns ...FindParentOptFn) {
|
||||
opts := &FindParentOption{
|
||||
MaxLevel: 10,
|
||||
OnlyOne: true,
|
||||
Collector: collectFn,
|
||||
}
|
||||
for _, fn := range optFns {
|
||||
fn(opts)
|
||||
}
|
||||
|
||||
FindInParentDirs(dirPath, func(currentDir string) bool {
|
||||
filePath := filepath.Join(currentDir, name)
|
||||
if fi, err := os.Stat(filePath); err == nil {
|
||||
found := false
|
||||
if fi.IsDir() {
|
||||
found = opts.NeedDir
|
||||
} else {
|
||||
found = !opts.NeedDir
|
||||
}
|
||||
|
||||
if found {
|
||||
opts.Collector(filePath)
|
||||
return !opts.OnlyOne
|
||||
}
|
||||
}
|
||||
return true
|
||||
}, opts.MaxLevel)
|
||||
}
|
||||
|
||||
// FindInParentDirs looks for file/dir in the current directory and parent directories
|
||||
// - MatchFunc custom matcher func. return false to stop find.
|
||||
func FindInParentDirs(dirPath string, matchFunc func(dir string) bool, maxLevel int) {
|
||||
currentLv := 1
|
||||
currentDir := ToAbsPath(dirPath)
|
||||
|
||||
for {
|
||||
// Check if the file exists in the current directory
|
||||
if !matchFunc(currentDir) {
|
||||
return
|
||||
}
|
||||
|
||||
// check find level
|
||||
if maxLevel > 0 && currentLv > maxLevel {
|
||||
break
|
||||
}
|
||||
|
||||
// Get parent directory
|
||||
parentDir := filepath.Dir(currentDir)
|
||||
if parentDir == currentDir {
|
||||
// Reached the root, file not found
|
||||
return
|
||||
}
|
||||
|
||||
// Move to parent directory
|
||||
currentLv++
|
||||
currentDir = parentDir
|
||||
}
|
||||
}
|
||||
|
||||
// SearchNameUp find file/dir name in dirPath or parent dirs,
|
||||
// return the name of directory path
|
||||
//
|
||||
@@ -158,14 +255,10 @@ type (
|
||||
)
|
||||
|
||||
// OnlyFindDir on find
|
||||
func OnlyFindDir(_ string, ent fs.DirEntry) bool {
|
||||
return ent.IsDir()
|
||||
}
|
||||
func OnlyFindDir(_ string, ent fs.DirEntry) bool { return ent.IsDir() }
|
||||
|
||||
// OnlyFindFile on find
|
||||
func OnlyFindFile(_ string, ent fs.DirEntry) bool {
|
||||
return !ent.IsDir()
|
||||
}
|
||||
func OnlyFindFile(_ string, ent fs.DirEntry) bool { return !ent.IsDir() }
|
||||
|
||||
// ExcludeNames on find
|
||||
func ExcludeNames(names ...string) FilterFunc {
|
||||
@@ -182,9 +275,7 @@ func IncludeSuffix(ss ...string) FilterFunc {
|
||||
}
|
||||
|
||||
// ExcludeDotFile on find
|
||||
func ExcludeDotFile(_ string, ent fs.DirEntry) bool {
|
||||
return ent.Name()[0] != '.'
|
||||
}
|
||||
func ExcludeDotFile(_ string, ent fs.DirEntry) bool { return ent.Name()[0] != '.' }
|
||||
|
||||
// ExcludeSuffix on find
|
||||
func ExcludeSuffix(ss ...string) FilterFunc {
|
||||
@@ -205,7 +296,7 @@ func ApplyFilters(fPath string, ent fs.DirEntry, filters []FilterFunc) bool {
|
||||
|
||||
// FindInDir code refer the go pkg: path/filepath.glob()
|
||||
//
|
||||
// - TIP: will be not found in sub-dir.
|
||||
// - TIP: default will be not found in sub-dir.
|
||||
//
|
||||
// filters: return false will skip the file.
|
||||
func FindInDir(dir string, handleFn HandleFunc, filters ...FilterFunc) (e error) {
|
||||
|
||||
38
vendor/github.com/gookit/goutil/fsutil/info.go
generated
vendored
38
vendor/github.com/gookit/goutil/fsutil/info.go
generated
vendored
@@ -9,12 +9,15 @@ import (
|
||||
)
|
||||
|
||||
// DirPath get dir path from filepath, without a last name.
|
||||
// eg: "/foo/bar/baz.js" => "/foo/bar"
|
||||
func DirPath(fPath string) string { return filepath.Dir(fPath) }
|
||||
|
||||
// Dir get dir path from filepath, without a last name.
|
||||
// eg: "/foo/bar/baz.js" => "/foo/bar"
|
||||
func Dir(fPath string) string { return filepath.Dir(fPath) }
|
||||
|
||||
// PathName get file/dir name from a full path
|
||||
// PathName get file/dir name from a full path.
|
||||
// eg: "/foo/bar/baz.js" => "baz.js"
|
||||
func PathName(fPath string) string { return filepath.Base(fPath) }
|
||||
|
||||
// PathNoExt get path from full path, without ext.
|
||||
@@ -30,7 +33,9 @@ func PathNoExt(fPath string) string {
|
||||
|
||||
// Name get file/dir name from full path.
|
||||
//
|
||||
// eg: path/to/main.go => "main.go"
|
||||
// eg:
|
||||
// "path/to/main.go" => "main.go"
|
||||
// "/foo/bar/baz" => "baz"
|
||||
func Name(fPath string) string {
|
||||
if fPath == "" {
|
||||
return ""
|
||||
@@ -74,16 +79,15 @@ func Extname(fPath string) string {
|
||||
func Suffix(fPath string) string { return filepath.Ext(fPath) }
|
||||
|
||||
// Expand will parse first `~` to user home dir path.
|
||||
func Expand(pathStr string) string {
|
||||
return comfunc.ExpandHome(pathStr)
|
||||
}
|
||||
func Expand(pathStr string) string { return comfunc.ExpandHome(pathStr) }
|
||||
|
||||
// ExpandHome will parse first `~` to user home dir path.
|
||||
func ExpandHome(pathStr string) string { return comfunc.ExpandHome(pathStr) }
|
||||
|
||||
// ExpandPath will parse `~` to user home dir path.
|
||||
func ExpandPath(pathStr string) string {
|
||||
return comfunc.ExpandHome(pathStr)
|
||||
}
|
||||
func ExpandPath(pathStr string) string { return comfunc.ExpandHome(pathStr) }
|
||||
|
||||
// ResolvePath will parse `~` and env var in path
|
||||
// ResolvePath will parse `~` and ENV var in path
|
||||
func ResolvePath(pathStr string) string {
|
||||
pathStr = comfunc.ExpandHome(pathStr)
|
||||
// return comfunc.ParseEnvVar()
|
||||
@@ -91,6 +95,18 @@ func ResolvePath(pathStr string) string {
|
||||
}
|
||||
|
||||
// SplitPath splits path immediately following the final Separator, separating it into a directory and file name component
|
||||
func SplitPath(pathStr string) (dir, name string) {
|
||||
return filepath.Split(pathStr)
|
||||
func SplitPath(pathStr string) (dir, name string) { return filepath.Split(pathStr) }
|
||||
|
||||
// homeDir cache
|
||||
var _homeDir string
|
||||
|
||||
// UserHomeDir is alias of os.UserHomeDir, but ignore error.(by os.UserHomeDir)
|
||||
func UserHomeDir() string {
|
||||
if _homeDir == "" {
|
||||
_homeDir, _ = os.UserHomeDir()
|
||||
}
|
||||
return _homeDir
|
||||
}
|
||||
|
||||
// HomeDir get user home dir path.
|
||||
func HomeDir() string { return UserHomeDir() }
|
||||
|
||||
17
vendor/github.com/gookit/goutil/fsutil/operate.go
generated
vendored
17
vendor/github.com/gookit/goutil/fsutil/operate.go
generated
vendored
@@ -13,12 +13,21 @@ import (
|
||||
)
|
||||
|
||||
// Mkdir alias of os.MkdirAll()
|
||||
func Mkdir(dirPath string, perm os.FileMode) error {
|
||||
return os.MkdirAll(dirPath, perm)
|
||||
func Mkdir(dirPath string, perm fs.FileMode) error { return os.MkdirAll(dirPath, perm) }
|
||||
|
||||
// MkdirQuick with default permission 0755.
|
||||
func MkdirQuick(dirPath string) error { return EnsureDir(dirPath) }
|
||||
|
||||
// EnsureDir creates a directory if it doesn't exist
|
||||
func EnsureDir(path string) error {
|
||||
if !DirExist(path) {
|
||||
return os.MkdirAll(path, 0755)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MkDirs batch makes multi dirs at once
|
||||
func MkDirs(perm os.FileMode, dirPaths ...string) error {
|
||||
func MkDirs(perm fs.FileMode, dirPaths ...string) error {
|
||||
for _, dirPath := range dirPaths {
|
||||
if err := os.MkdirAll(dirPath, perm); err != nil {
|
||||
return err
|
||||
@@ -28,7 +37,7 @@ func MkDirs(perm os.FileMode, dirPaths ...string) error {
|
||||
}
|
||||
|
||||
// MkSubDirs batch makes multi sub-dirs at once
|
||||
func MkSubDirs(perm os.FileMode, parentDir string, subDirs ...string) error {
|
||||
func MkSubDirs(perm fs.FileMode, parentDir string, subDirs ...string) error {
|
||||
for _, dirName := range subDirs {
|
||||
dirPath := parentDir + "/" + dirName
|
||||
if err := os.MkdirAll(dirPath, perm); err != nil {
|
||||
|
||||
14
vendor/github.com/gookit/goutil/fsutil/opwrite.go
generated
vendored
14
vendor/github.com/gookit/goutil/fsutil/opwrite.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package fsutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
@@ -185,3 +186,16 @@ func UpdateContents(filePath string, handleFn func(bs []byte) []byte) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateSymlink creates a symbolic link
|
||||
func CreateSymlink(target, linkPath string) error {
|
||||
// Check if the link already exists
|
||||
if IsFile(linkPath) {
|
||||
// Remove existing link/file
|
||||
if err := os.Remove(linkPath); err != nil {
|
||||
return fmt.Errorf("failed to remove existing symlink: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return os.Symlink(target, linkPath)
|
||||
}
|
||||
|
||||
1
vendor/github.com/gookit/goutil/goutil.go
generated
vendored
1
vendor/github.com/gookit/goutil/goutil.go
generated
vendored
@@ -206,4 +206,3 @@ func FuncName(f any) string {
|
||||
func PkgName(funcName string) string {
|
||||
return goinfo.PkgName(funcName)
|
||||
}
|
||||
|
||||
|
||||
6
vendor/github.com/gookit/goutil/group.go
generated
vendored
6
vendor/github.com/gookit/goutil/group.go
generated
vendored
@@ -12,11 +12,15 @@ import (
|
||||
type ErrGroup = syncs.ErrGroup
|
||||
|
||||
// NewCtxErrGroup instance. use for batch run tasks, can with context.
|
||||
//
|
||||
// Deprecated: use syncs.NewCtxErrGroup instead
|
||||
func NewCtxErrGroup(ctx context.Context, limit ...int) (*ErrGroup, context.Context) {
|
||||
return syncs.NewCtxErrGroup(ctx, limit...)
|
||||
}
|
||||
|
||||
// NewErrGroup instance. use for batch run tasks
|
||||
//
|
||||
// Deprecated: use syncs.NewErrGroup instead
|
||||
func NewErrGroup(limit ...int) *ErrGroup {
|
||||
return syncs.NewErrGroup(limit...)
|
||||
}
|
||||
@@ -47,7 +51,7 @@ func (p *QuickRun) Add(fns ...RunFn) *QuickRun {
|
||||
// Run all func
|
||||
func (p *QuickRun) Run() error {
|
||||
for i, fn := range p.fns {
|
||||
p.ctx.Set("index", i)
|
||||
p.ctx.Set("_index", i)
|
||||
if err := fn(p.ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
46
vendor/github.com/gookit/goutil/internal/checkfn/check.go
generated
vendored
46
vendor/github.com/gookit/goutil/internal/checkfn/check.go
generated
vendored
@@ -108,23 +108,57 @@ func Contains(data, elem any) (valid, found bool) {
|
||||
return true, false
|
||||
}
|
||||
|
||||
// StringsContains check string slice contains string
|
||||
func StringsContains(ss []string, s string) bool {
|
||||
// StringsContains check string slice contains sub-string
|
||||
func StringsContains(ss []string, sub string) bool {
|
||||
for _, v := range ss {
|
||||
if v == s {
|
||||
if v == sub {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// check is number: int or float
|
||||
var numReg = regexp.MustCompile(`^[-+]?\d*\.?\d+$`)
|
||||
var (
|
||||
// check is number: int or float
|
||||
numReg = regexp.MustCompile(`^[-+]?\d*\.?\d+$`)
|
||||
// is positive number: int or float
|
||||
pNumReg = regexp.MustCompile(`^\d*\.?\d+$`)
|
||||
)
|
||||
|
||||
// IsNumeric returns true if the given string is a numeric, otherwise false.
|
||||
func IsNumeric(s string) bool { return numReg.MatchString(s) }
|
||||
func IsNumeric(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
return numReg.MatchString(s)
|
||||
}
|
||||
|
||||
// IsPositiveNum check input string is positive number
|
||||
func IsPositiveNum(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
if s[0] == '-' {
|
||||
return false
|
||||
}
|
||||
return pNumReg.MatchString(s)
|
||||
}
|
||||
|
||||
// IsHttpURL check input is http/https url
|
||||
func IsHttpURL(s string) bool {
|
||||
return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://")
|
||||
}
|
||||
|
||||
// IndexByteAfter find index of byte after startIndex. return -1 if not found
|
||||
//
|
||||
// eg:
|
||||
//
|
||||
// IndexByteAfter("abcabc", 'b', 0) = 1
|
||||
// IndexByteAfter("abcabc", 'b', 2) = 4
|
||||
func IndexByteAfter(s string, b byte, startIndex int) int {
|
||||
idx := strings.IndexByte(s[startIndex:], b)
|
||||
if idx < 0 {
|
||||
return -1
|
||||
}
|
||||
return idx + startIndex
|
||||
}
|
||||
|
||||
33
vendor/github.com/gookit/goutil/internal/comfunc/convert.go
generated
vendored
33
vendor/github.com/gookit/goutil/internal/comfunc/convert.go
generated
vendored
@@ -43,6 +43,10 @@ func StrToBool(s string) (bool, error) {
|
||||
}
|
||||
|
||||
// FormatWithArgs format message with args
|
||||
//
|
||||
// - only one element, format to string
|
||||
// - first is format: fmt.Sprintf(firstElem, fmtAndArgs[1:]...)
|
||||
// - all is args: return fmt.Sprint(fmtAndArgs...)
|
||||
func FormatWithArgs(fmtAndArgs []any) string {
|
||||
ln := len(fmtAndArgs)
|
||||
if ln == 0 {
|
||||
@@ -50,16 +54,15 @@ func FormatWithArgs(fmtAndArgs []any) string {
|
||||
}
|
||||
|
||||
first := fmtAndArgs[0]
|
||||
|
||||
if ln == 1 {
|
||||
if msgAsStr, ok := first.(string); ok {
|
||||
return msgAsStr
|
||||
if str, ok := first.(string); ok {
|
||||
return str
|
||||
}
|
||||
return fmt.Sprintf("%+v", first)
|
||||
}
|
||||
|
||||
// is template string.
|
||||
if tplStr, ok := first.(string); ok {
|
||||
if tplStr, ok := first.(string); ok && strings.IndexByte(tplStr, '%') >= 0 {
|
||||
return fmt.Sprintf(tplStr, fmtAndArgs[1:]...)
|
||||
}
|
||||
return fmt.Sprint(fmtAndArgs...)
|
||||
@@ -86,11 +89,6 @@ var StrBySprintFn = func(v any) (string, error) {
|
||||
return fmt.Sprint(v), nil
|
||||
}
|
||||
|
||||
// WithHandlePtr set ConvOption.HandlePtr option
|
||||
func WithHandlePtr(opt *ConvOption) {
|
||||
opt.HandlePtr = true
|
||||
}
|
||||
|
||||
// WithUserConvFn set ConvOption.UserConvFn option
|
||||
func WithUserConvFn(fn comdef.ToStringFunc) ConvOptionFn {
|
||||
return func(opt *ConvOption) {
|
||||
@@ -116,11 +114,6 @@ func (opt *ConvOption) WithOption(optFns ...ConvOptionFn) {
|
||||
|
||||
// ToStringWith try to convert value to string. can with some option func, more see ConvOption.
|
||||
func ToStringWith(in any, optFns ...ConvOptionFn) (str string, err error) {
|
||||
opt := NewConvOption(optFns...)
|
||||
if !opt.NilAsFail && in == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
switch value := in.(type) {
|
||||
case int:
|
||||
str = strconv.Itoa(value)
|
||||
@@ -161,6 +154,18 @@ func ToStringWith(in any, optFns ...ConvOptionFn) (str string, err error) {
|
||||
case error:
|
||||
str = value.Error()
|
||||
default:
|
||||
if len(optFns) == 0 && in == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
opt := NewConvOption(optFns...)
|
||||
if in == nil {
|
||||
if opt.NilAsFail {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
|
||||
98
vendor/github.com/gookit/goutil/internal/comfunc/str_func.go
generated
vendored
98
vendor/github.com/gookit/goutil/internal/comfunc/str_func.go
generated
vendored
@@ -24,7 +24,7 @@ type ParseEnvLineOption struct {
|
||||
//
|
||||
// - It's like INI/ENV format contents.
|
||||
// - Support comments line starts with: "#", ";", "//"
|
||||
// - Support inline comments split with: " #" eg: name=tom # a comments
|
||||
// - Support inline comments split with: " #" eg: "name=tom # a comments"
|
||||
// - DON'T support submap parse.
|
||||
func ParseEnvLines(text string, opt ParseEnvLineOption) (mp map[string]string, err error) {
|
||||
lines := strings.Split(text, "\n")
|
||||
@@ -45,51 +45,91 @@ func ParseEnvLines(text string, opt ParseEnvLineOption) (mp map[string]string, e
|
||||
continue
|
||||
}
|
||||
|
||||
key, val := splitLineByChar(line, '=', !opt.NotInlineComments)
|
||||
// invalid line
|
||||
if strings.IndexByte(line, '=') < 1 {
|
||||
if key == "" {
|
||||
if opt.SkipOnErrorLine {
|
||||
continue
|
||||
}
|
||||
|
||||
strMap = nil
|
||||
err = fmt.Errorf("invalid line contents: must match `KEY=VAL`(line: %s)", line)
|
||||
return
|
||||
}
|
||||
|
||||
key, value := SplitLineToKv(line, "=")
|
||||
|
||||
// check and remove inline comments
|
||||
if !opt.NotInlineComments {
|
||||
if pos := strings.Index(value, " #"); pos > 0 {
|
||||
value = strings.TrimRight(value[0:pos], " \t")
|
||||
}
|
||||
}
|
||||
|
||||
strMap[key] = value
|
||||
strMap[key] = val
|
||||
}
|
||||
|
||||
return strMap, nil
|
||||
}
|
||||
|
||||
// SplitLineToKv parse string line to k-v. eg:
|
||||
// SplitLineToKv parse string line to k-v, not support comments.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// 'DEBUG=true' => ['DEBUG', 'true']
|
||||
//
|
||||
// NOTE: line must contain '=', allow: 'ENV_KEY='
|
||||
func SplitLineToKv(line, sep string) (string, string) {
|
||||
nodes := strings.SplitN(line, sep, 2)
|
||||
envKey := strings.TrimSpace(nodes[0])
|
||||
|
||||
// key cannot be empty
|
||||
if envKey == "" {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
if len(nodes) < 2 {
|
||||
if strings.Contains(line, sep) {
|
||||
return envKey, ""
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
return envKey, strings.TrimSpace(nodes[1])
|
||||
return SplitKvBySep(line, sep, false)
|
||||
}
|
||||
|
||||
// SplitKvBySep parse string line to k-v, support parse comments.
|
||||
// - rmInlineComments: check and remove inline comments by ' #'
|
||||
func SplitKvBySep(line, sep string, rmInlineComments bool) (key, val string) {
|
||||
sepPos := strings.Index(line, sep)
|
||||
if sepPos < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
return splitKvBySepPos(line, sepPos, len(sep), rmInlineComments)
|
||||
}
|
||||
|
||||
func splitLineByChar(line string, sep byte, rmInlineComments bool) (key, val string) {
|
||||
sepPos := strings.IndexByte(line, sep)
|
||||
if sepPos < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
return splitKvBySepPos(line, sepPos, 1, rmInlineComments)
|
||||
}
|
||||
|
||||
func splitKvBySepPos(line string, sepPos, sepLen int, rmInlineComments bool) (key, val string) {
|
||||
// key cannot be empty
|
||||
key = strings.TrimSpace(line[0:sepPos])
|
||||
if key == "" {
|
||||
return "", ""
|
||||
}
|
||||
val = strings.TrimSpace(line[sepPos+sepLen:])
|
||||
|
||||
// check quotes if present
|
||||
if vln := len(val); vln >= 2 {
|
||||
// remove quotes
|
||||
if (val[0] == '"' && val[vln-1] == '"') || (val[0] == '\'' && val[vln-1] == '\'') {
|
||||
val = val[1 : vln-1]
|
||||
return
|
||||
}
|
||||
|
||||
if !rmInlineComments {
|
||||
return
|
||||
}
|
||||
|
||||
// value is empty, only inline comments
|
||||
if val[0] == '#' {
|
||||
val = ""
|
||||
return
|
||||
}
|
||||
|
||||
// remove inline comments
|
||||
if pos := strings.Index(val, " #"); pos > 0 {
|
||||
val = strings.TrimRight(val[0:pos], " \t")
|
||||
vln = len(val)
|
||||
// remove quotes
|
||||
if (val[0] == '"' && val[vln-1] == '"') || (val[0] == '\'' && val[vln-1] == '\'') {
|
||||
val = val[1 : vln-1]
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
25
vendor/github.com/gookit/goutil/internal/comfunc/sysfunc.go
generated
vendored
25
vendor/github.com/gookit/goutil/internal/comfunc/sysfunc.go
generated
vendored
@@ -87,19 +87,24 @@ func CurrentShell(onlyName bool, fallbackShell ...string) (binPath string) {
|
||||
// 检查父进程名称
|
||||
parentProcess := os.Getenv("GOPROCESS")
|
||||
if parentProcess != "" {
|
||||
return parentProcess
|
||||
}
|
||||
|
||||
binPath = os.Getenv("SHELL") // 适用于 Unix-like 系统
|
||||
if len(binPath) == 0 {
|
||||
// TODO check on Windows
|
||||
binPath, err = ShellExec("echo $SHELL")
|
||||
if err != nil {
|
||||
return fbShell
|
||||
binPath = parentProcess
|
||||
} else {
|
||||
binPath = os.Getenv("SHELL") // 适用于 Unix-like 系统
|
||||
if len(binPath) == 0 {
|
||||
// TODO check on Windows git bash
|
||||
binPath, err = ShellExec("echo $SHELL")
|
||||
if err != nil {
|
||||
binPath = fbShell
|
||||
}
|
||||
}
|
||||
binPath = strings.TrimSpace(binPath)
|
||||
}
|
||||
|
||||
// fix: 去除 .exe 后缀
|
||||
if pos := strings.IndexByte(binPath, '.'); pos > 0 {
|
||||
binPath = binPath[:pos]
|
||||
}
|
||||
|
||||
binPath = strings.TrimSpace(binPath)
|
||||
// cache result
|
||||
curShellCache = binPath
|
||||
} else {
|
||||
|
||||
2
vendor/github.com/gookit/goutil/jsonutil/encoding.go
generated
vendored
2
vendor/github.com/gookit/goutil/jsonutil/encoding.go
generated
vendored
@@ -72,4 +72,4 @@ func DecodeFile(file string, ptr any) error {
|
||||
}
|
||||
|
||||
return json.Unmarshal(bs, ptr)
|
||||
}
|
||||
}
|
||||
|
||||
35
vendor/github.com/gookit/goutil/maputil/alias.go
generated
vendored
35
vendor/github.com/gookit/goutil/maputil/alias.go
generated
vendored
@@ -1,11 +1,15 @@
|
||||
package maputil
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Aliases implemented a simple string alias map.
|
||||
// - key: alias, value: real name
|
||||
type Aliases map[string]string
|
||||
|
||||
// AddAlias to the Aliases
|
||||
// AddAlias to the Aliases map
|
||||
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))
|
||||
@@ -13,21 +17,21 @@ func (as Aliases) AddAlias(alias, real string) {
|
||||
as[alias] = real
|
||||
}
|
||||
|
||||
// AddAliases to the Aliases
|
||||
// AddAliases to the Aliases map
|
||||
func (as Aliases) AddAliases(real string, aliases []string) {
|
||||
for _, a := range aliases {
|
||||
as.AddAlias(a, real)
|
||||
}
|
||||
}
|
||||
|
||||
// AddAliasMap to the Aliases
|
||||
// AddAliasMap to the Aliases map
|
||||
func (as Aliases) AddAliasMap(alias2real map[string]string) {
|
||||
for a, r := range alias2real {
|
||||
as.AddAlias(a, r)
|
||||
}
|
||||
}
|
||||
|
||||
// HasAlias in the Aliases
|
||||
// HasAlias in the Aliases map
|
||||
func (as Aliases) HasAlias(alias string) bool {
|
||||
if _, ok := as[alias]; ok {
|
||||
return true
|
||||
@@ -42,3 +46,24 @@ func (as Aliases) ResolveAlias(alias string) string {
|
||||
}
|
||||
return alias
|
||||
}
|
||||
|
||||
// AliasesNames returns all sorted alias names.
|
||||
func (as Aliases) AliasesNames() []string {
|
||||
ns := make([]string, 0, len(as))
|
||||
for alias := range as {
|
||||
ns = append(ns, alias)
|
||||
}
|
||||
sort.Strings(ns)
|
||||
return ns
|
||||
}
|
||||
|
||||
// GroupAliases groups aliases by real name.
|
||||
//
|
||||
// returns: {real name -> []aliases, ...}
|
||||
func (as Aliases) GroupAliases() map[string][]string {
|
||||
gaMap := make(map[string][]string)
|
||||
for alias, name := range as {
|
||||
gaMap[name] = append(gaMap[name], alias)
|
||||
}
|
||||
return gaMap
|
||||
}
|
||||
|
||||
15
vendor/github.com/gookit/goutil/maputil/convert.go
generated
vendored
15
vendor/github.com/gookit/goutil/maputil/convert.go
generated
vendored
@@ -86,7 +86,7 @@ func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V {
|
||||
}
|
||||
|
||||
// SliceToSMap convert string k-v pairs slice to map[string]string
|
||||
// - eg: []string{k1,v1,k2,v2} -> map[string]string{k1:v1, k2:v2}
|
||||
// - eg: []string{k1,v1,k2,v2} -> map[string]string{k1:v1, k2:v2}
|
||||
func SliceToSMap(kvPairs ...string) map[string]string {
|
||||
ln := len(kvPairs)
|
||||
// check kvPairs length must be even
|
||||
@@ -233,6 +233,19 @@ func FormatIndent(mp any, indent string) string {
|
||||
return NewFormatter(mp).WithIndent(indent).Format()
|
||||
}
|
||||
|
||||
// StrMapToText 将 map[string]string 转换为多行 key=value 格式文本
|
||||
func StrMapToText(m map[string]string) string {
|
||||
if len(m) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var lines []string
|
||||
for key, value := range m {
|
||||
lines = append(lines, key+"="+value)
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* Flat convert tree map to flatten key-value map.
|
||||
*************************************************************/
|
||||
|
||||
67
vendor/github.com/gookit/goutil/maputil/data.go
generated
vendored
67
vendor/github.com/gookit/goutil/maputil/data.go
generated
vendored
@@ -9,12 +9,12 @@ import (
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
// Data an map data type
|
||||
type Data map[string]any
|
||||
|
||||
// Map alias of Data
|
||||
type Map = Data
|
||||
|
||||
// Data alias of map[string]any
|
||||
type Data map[string]any
|
||||
|
||||
// Has value on the data map
|
||||
func (d Data) Has(key string) bool {
|
||||
_, ok := d.GetByPath(key)
|
||||
@@ -139,43 +139,70 @@ func (d Data) Default(key string, def any) any {
|
||||
return def
|
||||
}
|
||||
|
||||
// Int value get
|
||||
func (d Data) Int(key string) int {
|
||||
// Int value get, or default value
|
||||
func (d Data) Int(key string, defVal ...int) int {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return mathutil.QuietInt(val)
|
||||
return mathutil.SafeInt(val)
|
||||
}
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Int64 value get
|
||||
func (d Data) Int64(key string) int64 {
|
||||
// Int64 value get, or default value
|
||||
func (d Data) Int64(key string, defVal ...int64) int64 {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return mathutil.QuietInt64(val)
|
||||
return mathutil.SafeInt64(val)
|
||||
}
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Uint value get
|
||||
func (d Data) Uint(key string) uint {
|
||||
// Uint value get, or default value
|
||||
func (d Data) Uint(key string, defVal ...uint) uint {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return mathutil.QuietUint(val)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Uint64 value get
|
||||
func (d Data) Uint64(key string) uint64 {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return mathutil.QuietUint64(val)
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Str value gets by key
|
||||
func (d Data) Str(key string) string {
|
||||
// Uint16 value get, or default value
|
||||
func (d Data) Uint16(key string, defVal ...uint16) uint16 {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return uint16(mathutil.SafeUint(val))
|
||||
}
|
||||
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Uint64 value get, or default value
|
||||
func (d Data) Uint64(key string, defVal ...uint64) uint64 {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return mathutil.QuietUint64(val)
|
||||
}
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Str value gets by key, or default value
|
||||
func (d Data) Str(key string, defVal ...string) string {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return strutil.SafeString(val)
|
||||
}
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
24
vendor/github.com/gookit/goutil/maputil/maputil.go
generated
vendored
24
vendor/github.com/gookit/goutil/maputil/maputil.go
generated
vendored
@@ -16,6 +16,25 @@ const (
|
||||
KeySepChar = '.'
|
||||
)
|
||||
|
||||
// Copy copies all key/value pairs in src adding them to dst.
|
||||
// When a key in src is already present in dst,
|
||||
// the value in dst will be overwritten by the value associated
|
||||
// with the key in src.
|
||||
func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) {
|
||||
for k, v := range src {
|
||||
dst[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteFunc deletes any key/value pairs from m for which del returns true.
|
||||
func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool) {
|
||||
for k, v := range m {
|
||||
if del(k, v) {
|
||||
delete(m, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SimpleMerge simple merge two data map by string key. will merge the src to dst map
|
||||
func SimpleMerge(src, dst map[string]any) map[string]any {
|
||||
if len(src) == 0 {
|
||||
@@ -63,6 +82,11 @@ func MergeStrMap(src, dst map[string]string) map[string]string {
|
||||
return MergeStringMap(src, dst, false)
|
||||
}
|
||||
|
||||
// AppendSMap append string map data to dst map.
|
||||
func AppendSMap(dst, src map[string]string) map[string]string {
|
||||
return MergeStringMap(src, dst, false)
|
||||
}
|
||||
|
||||
// MergeStringMap simple merge two string map. merge src to dst map
|
||||
func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string {
|
||||
if len(src) == 0 {
|
||||
|
||||
2
vendor/github.com/gookit/goutil/maputil/smap.go
generated
vendored
2
vendor/github.com/gookit/goutil/maputil/smap.go
generated
vendored
@@ -5,6 +5,8 @@ import (
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
// SM is alias of map[string]string
|
||||
type SM = StrMap
|
||||
// SMap and StrMap is alias of map[string]string
|
||||
type SMap = StrMap
|
||||
type StrMap map[string]string
|
||||
|
||||
49
vendor/github.com/gookit/goutil/mathutil/check.go
generated
vendored
49
vendor/github.com/gookit/goutil/mathutil/check.go
generated
vendored
@@ -3,8 +3,26 @@ package mathutil
|
||||
import "github.com/gookit/goutil/comdef"
|
||||
|
||||
// IsNumeric returns true if the given character is a numeric, otherwise false.
|
||||
func IsNumeric(c byte) bool {
|
||||
return c >= '0' && c <= '9'
|
||||
func IsNumeric(c byte) bool { return c >= '0' && c <= '9' }
|
||||
|
||||
// IsInteger strict check the given value is an integer(intX,uintX), otherwise false.
|
||||
func IsInteger(val any) bool {
|
||||
switch val.(type) {
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsFloat returns true if the given character is a float(32/64), otherwise false.
|
||||
func IsFloat(val any) bool {
|
||||
switch val.(type) {
|
||||
case float32, float64:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Compare any intX,floatX value by given op. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
@@ -91,3 +109,30 @@ func InUintRange[T comdef.Uint](val, min, max T) bool {
|
||||
}
|
||||
return val >= min && val <= max
|
||||
}
|
||||
|
||||
// InDelta Check whether two floating-point numbers are equal within a specified margin of error
|
||||
//
|
||||
// Params:
|
||||
// want - 期望的浮点数值
|
||||
// give - 实际给定的浮点数值
|
||||
// delta - 允许的误差范围
|
||||
func InDelta[T comdef.Float](want, give T, delta float64) bool {
|
||||
diff := float64(want) - float64(give)
|
||||
if diff < 0 {
|
||||
diff = -diff
|
||||
}
|
||||
return diff <= delta
|
||||
}
|
||||
|
||||
// InDeltaAny Check whether two floating-point numbers are equal within a specified margin of error
|
||||
func InDeltaAny(want, give any, delta float64) bool {
|
||||
wantVal, err := ToFloat(want)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
giveVal, err := ToFloat(give)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return InDelta(wantVal, giveVal, delta)
|
||||
}
|
||||
67
vendor/github.com/gookit/goutil/mathutil/compare.go
generated
vendored
67
vendor/github.com/gookit/goutil/mathutil/compare.go
generated
vendored
@@ -74,3 +74,70 @@ func SwapMaxI64(x, y int64) (int64, int64) {
|
||||
func MaxFloat(x, y float64) float64 {
|
||||
return math.Max(x, y)
|
||||
}
|
||||
|
||||
// OrElse return default value on val is zero, else return val
|
||||
func OrElse[T comdef.Number](val, defVal T) T {
|
||||
return ZeroOr(val, defVal)
|
||||
}
|
||||
|
||||
// ZeroOr return default value on val is zero, else return val
|
||||
func ZeroOr[T comdef.Number](val, defVal T) T {
|
||||
if val != 0 {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
|
||||
// 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.Number](val, max, devVal T) T {
|
||||
if val < max {
|
||||
return val
|
||||
}
|
||||
return devVal
|
||||
}
|
||||
|
||||
// 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.Number](val, max, devVal T) T {
|
||||
if val <= max {
|
||||
return val
|
||||
}
|
||||
return devVal
|
||||
}
|
||||
|
||||
// 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.Number](val, min, defVal T) T {
|
||||
if val > min {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
|
||||
// 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.Number](val, min, defVal T) T {
|
||||
if val >= min {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
|
||||
648
vendor/github.com/gookit/goutil/mathutil/conv2int.go
generated
vendored
Normal file
648
vendor/github.com/gookit/goutil/mathutil/conv2int.go
generated
vendored
Normal file
@@ -0,0 +1,648 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/internal/checkfn"
|
||||
)
|
||||
|
||||
/*************************************************************
|
||||
* region convert to int
|
||||
*************************************************************/
|
||||
|
||||
// Int convert value to int
|
||||
func Int(in any) (int, error) { return ToInt(in) }
|
||||
|
||||
// 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) }
|
||||
|
||||
// IntOrPanic convert value to int, will panic on error
|
||||
func IntOrPanic(in any) int {
|
||||
val, err := ToInt(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// MustInt convert value to int, will panic on error
|
||||
func MustInt(in any) int { return IntOrPanic(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 := ToIntWith(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// IntOrErr convert value to int, return error on failed
|
||||
func IntOrErr(in any) (int, error) { return ToIntWith(in) }
|
||||
|
||||
// ToInt convert value to int, return error on failed
|
||||
func ToInt(in any) (int, error) { return ToIntWith(in) }
|
||||
|
||||
// ToIntWith convert value to int, can with some option func.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ToIntWithFunc(val, mathutil.WithNilAsFail, mathutil.WithUserConvFn(func(in any) (int, error) {
|
||||
// })
|
||||
func ToIntWith(in any, optFns ...ConvOptionFn[int]) (iVal int, err error) {
|
||||
if len(optFns) == 0 && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var opt *ConvOption[int]
|
||||
if len(optFns) > 0 {
|
||||
opt = NewConvOption(optFns...)
|
||||
if in == nil && opt.NilAsFail {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if tVal, ok := in.(string); ok {
|
||||
// in strict mode, cannot convert string to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
// try convert to int
|
||||
iVal, err = TryStrInt(tVal)
|
||||
return
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case int:
|
||||
iVal = tVal
|
||||
case *int: // default support int ptr type
|
||||
iVal = *tVal
|
||||
case int8:
|
||||
iVal = int(tVal)
|
||||
case int16:
|
||||
iVal = int(tVal)
|
||||
case int32:
|
||||
iVal = int(tVal)
|
||||
case int64:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case uint:
|
||||
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:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case uint64:
|
||||
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:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case comdef.Int64able: // eg: json.Number
|
||||
var i64 int64
|
||||
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:
|
||||
if opt == nil {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
iVal, err = opt.UserConvFn(in)
|
||||
} else if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToIntWith(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* region convert to int64
|
||||
*************************************************************/
|
||||
|
||||
// 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, _ := ToInt64With(in)
|
||||
return i64
|
||||
}
|
||||
|
||||
// QuietInt64 convert value to int64, will ignore error
|
||||
func QuietInt64(in any) int64 { return SafeInt64(in) }
|
||||
|
||||
// MustInt64 convert value to int64, will panic on error
|
||||
func MustInt64(in any) int64 {
|
||||
i64, err := ToInt64With(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return i64
|
||||
}
|
||||
|
||||
// Int64OrDefault convert value to int64, return default val on failed
|
||||
func Int64OrDefault(in any, defVal int64) int64 { return Int64Or(in, defVal) }
|
||||
|
||||
// Int64Or convert value to int64, return default val on failed
|
||||
func Int64Or(in any, defVal int64) int64 {
|
||||
i64, err := ToInt64With(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return i64
|
||||
}
|
||||
|
||||
// ToInt64 convert value to int64, return error on failed
|
||||
func ToInt64(in any) (int64, error) { return ToInt64With(in) }
|
||||
|
||||
// Int64OrErr convert value to int64, return error on failed
|
||||
func Int64OrErr(in any) (int64, error) { return ToInt64With(in) }
|
||||
|
||||
// ToInt64With try to convert value to int64. can with some option func, more see ConvOption.
|
||||
func ToInt64With(in any, optFns ...ConvOptionFn[int64]) (i64 int64, err error) {
|
||||
if len(optFns) == 0 && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var opt *ConvOption[int64]
|
||||
if len(optFns) > 0 {
|
||||
opt = NewConvOption(optFns...)
|
||||
if in == nil && opt.NilAsFail {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if tVal, ok := in.(string); ok {
|
||||
// in strict mode, cannot convert string to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
// try convert to int64
|
||||
i64, err = TryStrInt64(tVal)
|
||||
return
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case int:
|
||||
i64 = int64(tVal)
|
||||
case int8:
|
||||
i64 = int64(tVal)
|
||||
case int16:
|
||||
i64 = int64(tVal)
|
||||
case int32:
|
||||
i64 = int64(tVal)
|
||||
case int64:
|
||||
i64 = tVal
|
||||
case *int64: // default support int64 ptr type
|
||||
i64 = *tVal
|
||||
case uint:
|
||||
i64 = int64(tVal)
|
||||
case uint8:
|
||||
i64 = int64(tVal)
|
||||
case uint16:
|
||||
i64 = int64(tVal)
|
||||
case uint32:
|
||||
i64 = int64(tVal)
|
||||
case uint64:
|
||||
i64 = int64(tVal)
|
||||
case float32:
|
||||
// in strict mode, cannot convert float to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
i64 = int64(tVal)
|
||||
case float64:
|
||||
// in strict mode, cannot convert float to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
if tVal > math.MaxInt64 {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
i64 = int64(tVal)
|
||||
case time.Duration:
|
||||
i64 = int64(tVal)
|
||||
case comdef.Int64able: // eg: json.Number
|
||||
i64, err = tVal.Int64()
|
||||
default:
|
||||
if opt == nil {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
i64, err = opt.UserConvFn(in)
|
||||
} else if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToInt64With(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* region convert to uint
|
||||
*************************************************************/
|
||||
|
||||
// Uint convert any to uint, return error on failed
|
||||
func Uint(in any) (uint, error) { return ToUint(in) }
|
||||
|
||||
// SafeUint convert any to uint, will ignore error
|
||||
func SafeUint(in any) uint {
|
||||
val, _ := ToUint(in)
|
||||
return val
|
||||
}
|
||||
|
||||
// QuietUint convert any to uint, will ignore error
|
||||
func QuietUint(in any) uint { return SafeUint(in) }
|
||||
|
||||
// MustUint convert any to uint, will panic on error
|
||||
func MustUint(in any) uint {
|
||||
val, err := ToUintWith(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// UintOrDefault convert any to uint, return default val on failed
|
||||
func UintOrDefault(in any, defVal uint) uint { return UintOr(in, defVal) }
|
||||
|
||||
// UintOr convert any to uint, return default val on failed
|
||||
func UintOr(in any, defVal uint) uint {
|
||||
val, err := ToUintWith(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// UintOrErr convert value to uint, return error on failed
|
||||
func UintOrErr(in any) (uint, error) { return ToUintWith(in) }
|
||||
|
||||
// ToUint convert value to uint, return error on failed
|
||||
func ToUint(in any) (u64 uint, err error) { return ToUintWith(in) }
|
||||
|
||||
// ToUintWith try to convert value to uint. can with some option func, more see ConvOption.
|
||||
func ToUintWith(in any, optFns ...ConvOptionFn[uint]) (uVal uint, err error) {
|
||||
if len(optFns) == 0 && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var opt *ConvOption[uint]
|
||||
if len(optFns) > 0 {
|
||||
opt = NewConvOption(optFns...)
|
||||
if in == nil && opt.NilAsFail {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if tVal, ok := in.(string); ok {
|
||||
// in strict mode, cannot convert string to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
// try convert to uint64
|
||||
var u64 uint64
|
||||
if u64, err = TryStrUint64(tVal); err == nil {
|
||||
uVal = uint(u64)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case int:
|
||||
uVal = uint(tVal)
|
||||
case int8:
|
||||
uVal = uint(tVal)
|
||||
case int16:
|
||||
uVal = uint(tVal)
|
||||
case int32:
|
||||
uVal = uint(tVal)
|
||||
case int64:
|
||||
uVal = uint(tVal)
|
||||
case uint:
|
||||
uVal = tVal
|
||||
case *uint: // default support uint ptr type
|
||||
uVal = *tVal
|
||||
case uint8:
|
||||
uVal = uint(tVal)
|
||||
case uint16:
|
||||
uVal = uint(tVal)
|
||||
case uint32:
|
||||
uVal = uint(tVal)
|
||||
case uint64:
|
||||
uVal = uint(tVal)
|
||||
case float32:
|
||||
uVal = uint(tVal)
|
||||
case float64:
|
||||
uVal = uint(tVal)
|
||||
case time.Duration:
|
||||
uVal = uint(tVal)
|
||||
case comdef.Int64able: // eg: json.Number
|
||||
var i64 int64
|
||||
i64, err = tVal.Int64()
|
||||
uVal = uint(i64)
|
||||
default:
|
||||
if opt == nil {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
uVal, err = opt.UserConvFn(in)
|
||||
} else if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToUintWith(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* region convert to uint64
|
||||
*************************************************************/
|
||||
|
||||
// Uint64 convert any to uint64, return error on failed
|
||||
func Uint64(in any) (uint64, error) { return ToUint64(in) }
|
||||
|
||||
// QuietUint64 convert any to uint64, will ignore error
|
||||
func QuietUint64(in any) uint64 { return SafeUint64(in) }
|
||||
|
||||
// SafeUint64 convert any to uint64, will ignore error
|
||||
func SafeUint64(in any) uint64 {
|
||||
val, _ := ToUint64(in)
|
||||
return val
|
||||
}
|
||||
|
||||
// MustUint64 convert any to uint64, will panic on error
|
||||
func MustUint64(in any) uint64 {
|
||||
val, err := ToUint64With(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Uint64OrDefault convert any to uint64, return default val on failed
|
||||
func Uint64OrDefault(in any, defVal uint64) uint64 { return Uint64Or(in, defVal) }
|
||||
|
||||
// Uint64Or convert any to uint64, return default val on failed
|
||||
func Uint64Or(in any, defVal uint64) uint64 {
|
||||
val, err := ToUint64With(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Uint64OrErr convert value to uint64, return error on failed
|
||||
func Uint64OrErr(in any) (uint64, error) { return ToUint64With(in) }
|
||||
|
||||
// ToUint64 convert value to uint64, return error on failed
|
||||
func ToUint64(in any) (uint64, error) { return ToUint64With(in) }
|
||||
|
||||
// ToUint64With try to convert value to uint64. can with some option func, more see ConvOption.
|
||||
func ToUint64With(in any, optFns ...ConvOptionFn[uint64]) (u64 uint64, err error) {
|
||||
if len(optFns) == 0 && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var opt *ConvOption[uint64]
|
||||
if len(optFns) > 0 {
|
||||
opt = NewConvOption(optFns...)
|
||||
if in == nil && opt.NilAsFail {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if tVal, ok := in.(string); ok {
|
||||
// in strict mode, cannot convert string to int
|
||||
if opt != nil && opt.StrictMode {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
// try convert to uint64
|
||||
u64, err = TryStrUint64(tVal)
|
||||
return
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case int:
|
||||
u64 = uint64(tVal)
|
||||
case int8:
|
||||
u64 = uint64(tVal)
|
||||
case int16:
|
||||
u64 = uint64(tVal)
|
||||
case int32:
|
||||
u64 = uint64(tVal)
|
||||
case int64:
|
||||
u64 = uint64(tVal)
|
||||
case uint:
|
||||
u64 = uint64(tVal)
|
||||
case uint8:
|
||||
u64 = uint64(tVal)
|
||||
case uint16:
|
||||
u64 = uint64(tVal)
|
||||
case uint32:
|
||||
u64 = uint64(tVal)
|
||||
case uint64:
|
||||
u64 = tVal
|
||||
case *uint64: // default support uint64 ptr type
|
||||
u64 = *tVal
|
||||
case float32:
|
||||
u64 = uint64(tVal)
|
||||
case float64:
|
||||
u64 = uint64(tVal)
|
||||
case time.Duration:
|
||||
u64 = uint64(tVal)
|
||||
case comdef.Int64able: // eg: json.Number
|
||||
var i64 int64
|
||||
i64, err = tVal.Int64()
|
||||
u64 = uint64(i64)
|
||||
default:
|
||||
if opt == nil {
|
||||
err = comdef.ErrConvType
|
||||
return
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
u64, err = opt.UserConvFn(in)
|
||||
} else if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToUint64With(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* region string to intX/uintX
|
||||
*************************************************************/
|
||||
|
||||
// StrInt convert string to int, ignore error
|
||||
func StrInt(s string) int {
|
||||
iVal, _ := strconv.Atoi(strings.TrimSpace(s))
|
||||
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
|
||||
}
|
||||
|
||||
// TryStrInt convert string to int, return error on failed.
|
||||
//
|
||||
// - empty string will return 0.
|
||||
// - allow float string.
|
||||
func TryStrInt(s string) (int, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// try convert to int
|
||||
iVal, err := strconv.Atoi(s)
|
||||
|
||||
// handle the case where the string might be a float
|
||||
if err != nil && checkfn.IsNumeric(s) {
|
||||
var floatVal float64
|
||||
if floatVal, err = strconv.ParseFloat(s, 64); err == nil {
|
||||
iVal = int(math.Round(floatVal))
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return iVal, err
|
||||
}
|
||||
|
||||
// TryStrInt64 convert string to int64, return error on failed.
|
||||
//
|
||||
// - empty string will return 0.
|
||||
// - allow float string.
|
||||
func TryStrInt64(s string) (int64, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return 0, nil
|
||||
}
|
||||
i64, err := strconv.ParseInt(s, 10, 0)
|
||||
|
||||
// handle the case where the string might be a float
|
||||
if err != nil && checkfn.IsNumeric(s) {
|
||||
var floatVal float64
|
||||
if floatVal, err = strconv.ParseFloat(s, 64); err == nil {
|
||||
i64 = int64(math.Round(floatVal))
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return i64, err
|
||||
}
|
||||
|
||||
// TryStrUint64 try to convert string to uint64, return error on failed
|
||||
//
|
||||
// - empty string will return 0.
|
||||
// - allow float string.
|
||||
func TryStrUint64(s string) (uint64, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// try convert to int64
|
||||
u64, err := strconv.ParseUint(s, 10, 0)
|
||||
|
||||
// handle the case where the string might be a float
|
||||
if err != nil && checkfn.IsPositiveNum(s) {
|
||||
var floatVal float64
|
||||
if floatVal, err = strconv.ParseFloat(s, 64); err == nil {
|
||||
u64 = uint64(math.Round(floatVal))
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return u64, err
|
||||
}
|
||||
545
vendor/github.com/gookit/goutil/mathutil/convert.go
generated
vendored
545
vendor/github.com/gookit/goutil/mathutil/convert.go
generated
vendored
@@ -1,8 +1,6 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -13,24 +11,6 @@ import (
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
)
|
||||
|
||||
// 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) (uint, error)
|
||||
|
||||
// ToUint64Func convert value to uint
|
||||
type ToUint64Func func(any) (uint64, error)
|
||||
|
||||
// ToFloatFunc convert value to float
|
||||
type ToFloatFunc func(any) (float64, error)
|
||||
|
||||
// ToTypeFunc convert value to defined type
|
||||
type ToTypeFunc[T any] func(any) (T, error)
|
||||
|
||||
// ConvOption convert options
|
||||
type ConvOption[T any] struct {
|
||||
// if ture: value is nil, will return convert error;
|
||||
@@ -40,6 +20,11 @@ type ConvOption[T any] struct {
|
||||
// - if true: will use real type try convert. default is false
|
||||
// - NOTE: current T type's ptr is default support.
|
||||
HandlePtr bool
|
||||
// StrictMode for convert value. default is false
|
||||
//
|
||||
// TRUE:
|
||||
// - to int: string, float will return error
|
||||
StrictMode bool
|
||||
// set custom fallback convert func for not supported type.
|
||||
UserConvFn ToTypeFunc[T]
|
||||
}
|
||||
@@ -68,14 +53,13 @@ type ConvOptionFn[T any] func(opt *ConvOption[T])
|
||||
// Example:
|
||||
//
|
||||
// ToIntWithFunc(val, mathutil.WithNilAsFail[int])
|
||||
func WithNilAsFail[T any](opt *ConvOption[T]) {
|
||||
opt.NilAsFail = true
|
||||
}
|
||||
func WithNilAsFail[T any](opt *ConvOption[T]) { opt.NilAsFail = true }
|
||||
|
||||
// WithHandlePtr set ConvOption.HandlePtr option
|
||||
func WithHandlePtr[T any](opt *ConvOption[T]) {
|
||||
opt.HandlePtr = true
|
||||
}
|
||||
func WithHandlePtr[T any](opt *ConvOption[T]) { opt.HandlePtr = true }
|
||||
|
||||
// WithStrictMode set ConvOption.StrictMode option
|
||||
func WithStrictMode[T any](opt *ConvOption[T]) { opt.StrictMode = true }
|
||||
|
||||
// WithUserConvFn set ConvOption.UserConvFn option
|
||||
func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T] {
|
||||
@@ -85,488 +69,71 @@ func WithUserConvFn[T any](fn ToTypeFunc[T]) ConvOptionFn[T] {
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert value to int
|
||||
* region Strict to int/uint
|
||||
*************************************************************/
|
||||
|
||||
// Int convert value to int
|
||||
func Int(in any) (int, error) { return ToInt(in) }
|
||||
|
||||
// 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) }
|
||||
|
||||
// IntOrPanic convert value to int, will panic on error
|
||||
func IntOrPanic(in any) int {
|
||||
val, err := ToInt(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// MustInt convert value to int, will panic on error
|
||||
func MustInt(in any) int { return IntOrPanic(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 := ToIntWith(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// IntOrErr convert value to int, return error on failed
|
||||
func IntOrErr(in any) (int, error) { return ToIntWith(in) }
|
||||
|
||||
// ToInt convert value to int, return error on failed
|
||||
func ToInt(in any) (int, error) { return ToIntWith(in) }
|
||||
|
||||
// ToIntWith convert value to int, can with some option func.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ToIntWithFunc(val, mathutil.WithNilAsFail, mathutil.WithUserConvFn(func(in any) (int, error) {
|
||||
// })
|
||||
func ToIntWith(in any, optFns ...ConvOptionFn[int]) (iVal int, err error) {
|
||||
opt := NewConvOption[int](optFns...)
|
||||
if !opt.NilAsFail && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
// StrictInt check the given value is an integer(intX,uintX), return the int64 value and true if success
|
||||
func StrictInt(val any) (int64, bool) {
|
||||
switch tVal := val.(type) {
|
||||
case int:
|
||||
iVal = tVal
|
||||
case *int: // default support int ptr type
|
||||
iVal = *tVal
|
||||
return int64(tVal), true
|
||||
case int8:
|
||||
iVal = int(tVal)
|
||||
return int64(tVal), true
|
||||
case int16:
|
||||
iVal = int(tVal)
|
||||
return int64(tVal), true
|
||||
case int32:
|
||||
iVal = int(tVal)
|
||||
return int64(tVal), true
|
||||
case int64:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
return tVal, true
|
||||
case uint:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
return int64(tVal), true
|
||||
case uint8:
|
||||
iVal = int(tVal)
|
||||
return int64(tVal), true
|
||||
case uint16:
|
||||
iVal = int(tVal)
|
||||
return int64(tVal), true
|
||||
case uint32:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
return int64(tVal), true
|
||||
case uint64:
|
||||
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:
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case string:
|
||||
sVal := strings.TrimSpace(tVal)
|
||||
iVal, err = strconv.Atoi(sVal)
|
||||
// handle the case where the string might be a float
|
||||
if err != nil && checkfn.IsNumeric(sVal) {
|
||||
var floatVal float64
|
||||
if floatVal, err = strconv.ParseFloat(sVal, 64); err == nil {
|
||||
iVal = int(math.Round(floatVal))
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
case comdef.Int64able: // eg: json.Number
|
||||
var i64 int64
|
||||
if i64, err = tVal.Int64(); err == nil {
|
||||
if i64 > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(i64)
|
||||
}
|
||||
}
|
||||
return int64(tVal), true
|
||||
case uintptr:
|
||||
return int64(tVal), true
|
||||
default:
|
||||
if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToIntWith(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
return opt.UserConvFn(in)
|
||||
}
|
||||
err = comdef.ErrConvType
|
||||
return 0, false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// StrInt convert.
|
||||
func StrInt(s string) int {
|
||||
iVal, _ := strconv.Atoi(strings.TrimSpace(s))
|
||||
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
|
||||
// StrictUint strict check value is integer(intX,uintX) and convert to uint64.
|
||||
func StrictUint(val any) (uint64, bool) {
|
||||
switch tVal := val.(type) {
|
||||
case int:
|
||||
return uint64(tVal), true
|
||||
case int8:
|
||||
return uint64(tVal), true
|
||||
case int16:
|
||||
return uint64(tVal), true
|
||||
case int32:
|
||||
return uint64(tVal), true
|
||||
case int64:
|
||||
return uint64(tVal), true
|
||||
case uint:
|
||||
return uint64(tVal), true
|
||||
case uint8:
|
||||
return uint64(tVal), true
|
||||
case uint16:
|
||||
return uint64(tVal), true
|
||||
case uint32:
|
||||
return uint64(tVal), true
|
||||
case uint64:
|
||||
return tVal, true
|
||||
case uintptr:
|
||||
return uint64(tVal), true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
return iVal
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert value to int64
|
||||
*************************************************************/
|
||||
|
||||
// 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, _ := ToInt64With(in)
|
||||
return i64
|
||||
}
|
||||
|
||||
// QuietInt64 convert value to int64, will ignore error
|
||||
func QuietInt64(in any) int64 { return SafeInt64(in) }
|
||||
|
||||
// MustInt64 convert value to int64, will panic on error
|
||||
func MustInt64(in any) int64 {
|
||||
i64, err := ToInt64With(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return i64
|
||||
}
|
||||
|
||||
// Int64OrDefault convert value to int64, return default val on failed
|
||||
func Int64OrDefault(in any, defVal int64) int64 { return Int64Or(in, defVal) }
|
||||
|
||||
// Int64Or convert value to int64, return default val on failed
|
||||
func Int64Or(in any, defVal int64) int64 {
|
||||
i64, err := ToInt64With(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return i64
|
||||
}
|
||||
|
||||
// ToInt64 convert value to int64, return error on failed
|
||||
func ToInt64(in any) (int64, error) { return ToInt64With(in) }
|
||||
|
||||
// Int64OrErr convert value to int64, return error on failed
|
||||
func Int64OrErr(in any) (int64, error) { return ToInt64With(in) }
|
||||
|
||||
// ToInt64With try to convert value to int64. can with some option func, more see ConvOption.
|
||||
func ToInt64With(in any, optFns ...ConvOptionFn[int64]) (i64 int64, err error) {
|
||||
opt := NewConvOption(optFns...)
|
||||
if !opt.NilAsFail && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case string:
|
||||
sVal := strings.TrimSpace(tVal)
|
||||
i64, err = strconv.ParseInt(sVal, 10, 0)
|
||||
// handle the case where the string might be a float
|
||||
if err != nil && checkfn.IsNumeric(sVal) {
|
||||
var floatVal float64
|
||||
if floatVal, err = strconv.ParseFloat(sVal, 64); err == nil {
|
||||
i64 = int64(math.Round(floatVal))
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
case int:
|
||||
i64 = int64(tVal)
|
||||
case int8:
|
||||
i64 = int64(tVal)
|
||||
case int16:
|
||||
i64 = int64(tVal)
|
||||
case int32:
|
||||
i64 = int64(tVal)
|
||||
case int64:
|
||||
i64 = tVal
|
||||
case *int64: // default support int64 ptr type
|
||||
i64 = *tVal
|
||||
case uint:
|
||||
i64 = int64(tVal)
|
||||
case uint8:
|
||||
i64 = int64(tVal)
|
||||
case uint16:
|
||||
i64 = int64(tVal)
|
||||
case uint32:
|
||||
i64 = int64(tVal)
|
||||
case uint64:
|
||||
i64 = int64(tVal)
|
||||
case float32:
|
||||
i64 = int64(tVal)
|
||||
case float64:
|
||||
i64 = int64(tVal)
|
||||
case time.Duration:
|
||||
i64 = int64(tVal)
|
||||
case comdef.Int64able: // eg: json.Number
|
||||
i64, err = tVal.Int64()
|
||||
default:
|
||||
if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToInt64With(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
i64, err = opt.UserConvFn(in)
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert value to uint
|
||||
*************************************************************/
|
||||
|
||||
// Uint convert any to uint, return error on failed
|
||||
func Uint(in any) (uint, error) { return ToUint(in) }
|
||||
|
||||
// SafeUint convert any to uint, will ignore error
|
||||
func SafeUint(in any) uint {
|
||||
val, _ := ToUint(in)
|
||||
return val
|
||||
}
|
||||
|
||||
// QuietUint convert any to uint, will ignore error
|
||||
func QuietUint(in any) uint { return SafeUint(in) }
|
||||
|
||||
// MustUint convert any to uint, will panic on error
|
||||
func MustUint(in any) uint {
|
||||
val, err := ToUintWith(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// UintOrDefault convert any to uint, return default val on failed
|
||||
func UintOrDefault(in any, defVal uint) uint { return UintOr(in, defVal) }
|
||||
|
||||
// UintOr convert any to uint, return default val on failed
|
||||
func UintOr(in any, defVal uint) uint {
|
||||
val, err := ToUintWith(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// UintOrErr convert value to uint, return error on failed
|
||||
func UintOrErr(in any) (uint, error) { return ToUintWith(in) }
|
||||
|
||||
// ToUint convert value to uint, return error on failed
|
||||
func ToUint(in any) (u64 uint, err error) { return ToUintWith(in) }
|
||||
|
||||
// ToUintWith try to convert value to uint. can with some option func, more see ConvOption.
|
||||
func ToUintWith(in any, optFns ...ConvOptionFn[uint]) (uVal uint, err error) {
|
||||
opt := NewConvOption(optFns...)
|
||||
if !opt.NilAsFail && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case int:
|
||||
uVal = uint(tVal)
|
||||
case int8:
|
||||
uVal = uint(tVal)
|
||||
case int16:
|
||||
uVal = uint(tVal)
|
||||
case int32:
|
||||
uVal = uint(tVal)
|
||||
case int64:
|
||||
uVal = uint(tVal)
|
||||
case uint:
|
||||
uVal = tVal
|
||||
case *uint: // default support uint ptr type
|
||||
uVal = *tVal
|
||||
case uint8:
|
||||
uVal = uint(tVal)
|
||||
case uint16:
|
||||
uVal = uint(tVal)
|
||||
case uint32:
|
||||
uVal = uint(tVal)
|
||||
case uint64:
|
||||
uVal = uint(tVal)
|
||||
case float32:
|
||||
uVal = uint(tVal)
|
||||
case float64:
|
||||
uVal = uint(tVal)
|
||||
case time.Duration:
|
||||
uVal = uint(tVal)
|
||||
case comdef.Int64able: // eg: json.Number
|
||||
var i64 int64
|
||||
i64, err = tVal.Int64()
|
||||
uVal = uint(i64)
|
||||
case string:
|
||||
var u64 uint64
|
||||
u64, err = strconv.ParseUint(strings.TrimSpace(tVal), 10, 0)
|
||||
uVal = uint(u64)
|
||||
default:
|
||||
if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToUintWith(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
uVal, err = opt.UserConvFn(in)
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert value to uint64
|
||||
*************************************************************/
|
||||
|
||||
// Uint64 convert any to uint64, return error on failed
|
||||
func Uint64(in any) (uint64, error) { return ToUint64(in) }
|
||||
|
||||
// QuietUint64 convert any to uint64, will ignore error
|
||||
func QuietUint64(in any) uint64 { return SafeUint64(in) }
|
||||
|
||||
// SafeUint64 convert any to uint64, will ignore error
|
||||
func SafeUint64(in any) uint64 {
|
||||
val, _ := ToUint64(in)
|
||||
return val
|
||||
}
|
||||
|
||||
// MustUint64 convert any to uint64, will panic on error
|
||||
func MustUint64(in any) uint64 {
|
||||
val, err := ToUint64With(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Uint64OrDefault convert any to uint64, return default val on failed
|
||||
func Uint64OrDefault(in any, defVal uint64) uint64 { return Uint64Or(in, defVal) }
|
||||
|
||||
// Uint64Or convert any to uint64, return default val on failed
|
||||
func Uint64Or(in any, defVal uint64) uint64 {
|
||||
val, err := ToUint64With(in)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Uint64OrErr convert value to uint64, return error on failed
|
||||
func Uint64OrErr(in any) (uint64, error) { return ToUint64With(in) }
|
||||
|
||||
// ToUint64 convert value to uint64, return error on failed
|
||||
func ToUint64(in any) (uint64, error) { return ToUint64With(in) }
|
||||
|
||||
// ToUint64With try to convert value to uint64. can with some option func, more see ConvOption.
|
||||
func ToUint64With(in any, optFns ...ConvOptionFn[uint64]) (u64 uint64, err error) {
|
||||
opt := NewConvOption(optFns...)
|
||||
if !opt.NilAsFail && in == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
switch tVal := in.(type) {
|
||||
case int:
|
||||
u64 = uint64(tVal)
|
||||
case int8:
|
||||
u64 = uint64(tVal)
|
||||
case int16:
|
||||
u64 = uint64(tVal)
|
||||
case int32:
|
||||
u64 = uint64(tVal)
|
||||
case int64:
|
||||
u64 = uint64(tVal)
|
||||
case uint:
|
||||
u64 = uint64(tVal)
|
||||
case uint8:
|
||||
u64 = uint64(tVal)
|
||||
case uint16:
|
||||
u64 = uint64(tVal)
|
||||
case uint32:
|
||||
u64 = uint64(tVal)
|
||||
case uint64:
|
||||
u64 = tVal
|
||||
case *uint64: // default support uint64 ptr type
|
||||
u64 = *tVal
|
||||
case float32:
|
||||
u64 = uint64(tVal)
|
||||
case float64:
|
||||
u64 = uint64(tVal)
|
||||
case time.Duration:
|
||||
u64 = uint64(tVal)
|
||||
case comdef.Int64able: // 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:
|
||||
if opt.HandlePtr {
|
||||
if rv := reflect.ValueOf(in); rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
if checkfn.IsSimpleKind(rv.Kind()) {
|
||||
return ToUint64With(rv.Interface(), optFns...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opt.UserConvFn != nil {
|
||||
u64, err = opt.UserConvFn(in)
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert value to float64
|
||||
* region convert to float64
|
||||
*************************************************************/
|
||||
|
||||
// QuietFloat convert value to float64, will ignore error. alias of SafeFloat
|
||||
@@ -671,7 +238,7 @@ func ToFloatWith(in any, optFns ...ConvOptionFn[float64]) (f64 float64, err erro
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert intX/floatX to string
|
||||
* region intX/floatX to string
|
||||
*************************************************************/
|
||||
|
||||
// MustString convert intX/floatX value to string, will panic on error
|
||||
|
||||
15
vendor/github.com/gookit/goutil/mathutil/format.go
generated
vendored
15
vendor/github.com/gookit/goutil/mathutil/format.go
generated
vendored
@@ -22,6 +22,21 @@ func DataSize(size uint64) string {
|
||||
}
|
||||
}
|
||||
|
||||
// FormatBytes Format the byte size to be a readable string. eg: 1024 => 1 KB
|
||||
func FormatBytes(bytes int) string {
|
||||
const unit = 1024
|
||||
if bytes < unit {
|
||||
return fmt.Sprintf("%d B", bytes)
|
||||
}
|
||||
|
||||
div, exp := int64(unit), 0
|
||||
for n := bytes / unit; n >= unit; n /= unit {
|
||||
div *= unit
|
||||
exp++
|
||||
}
|
||||
return fmt.Sprintf("%.2f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
|
||||
}
|
||||
|
||||
var timeFormats = [][]int{
|
||||
{0},
|
||||
{1},
|
||||
|
||||
167
vendor/github.com/gookit/goutil/mathutil/mathutil.go
generated
vendored
167
vendor/github.com/gookit/goutil/mathutil/mathutil.go
generated
vendored
@@ -2,78 +2,15 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/internal/checkfn"
|
||||
)
|
||||
|
||||
// OrElse return default value on val is zero, else return val
|
||||
func OrElse[T comdef.Number](val, defVal T) T {
|
||||
return ZeroOr(val, defVal)
|
||||
}
|
||||
|
||||
// ZeroOr return default value on val is zero, else return val
|
||||
func ZeroOr[T comdef.Number](val, defVal T) T {
|
||||
if val != 0 {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
|
||||
// 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.Number](val, max, devVal T) T {
|
||||
if val < max {
|
||||
return val
|
||||
}
|
||||
return devVal
|
||||
}
|
||||
|
||||
// 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.Number](val, max, devVal T) T {
|
||||
if val <= max {
|
||||
return val
|
||||
}
|
||||
return devVal
|
||||
}
|
||||
|
||||
// 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.Number](val, min, defVal T) T {
|
||||
if val > min {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
|
||||
// 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.Number](val, min, defVal T) T {
|
||||
if val >= min {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
|
||||
// Mul computes the `a*b` value, rounding the result.
|
||||
func Mul[T1, T2 comdef.Number](a T1, b T2) float64 {
|
||||
return math.Round(SafeFloat(a) * SafeFloat(b))
|
||||
@@ -100,10 +37,104 @@ func DivF2i(a, b float64) int {
|
||||
return int(math.Round(a / b))
|
||||
}
|
||||
|
||||
// Percent returns a value percentage of the total
|
||||
// Percent returns a value percentage of the total. eg: 1/100 = 1.0%
|
||||
func Percent(val, total int) float64 {
|
||||
if total == 0 {
|
||||
return float64(0)
|
||||
}
|
||||
return (float64(val) / float64(total)) * 100
|
||||
}
|
||||
|
||||
// Range a number range expression, and handle each value. eg: "1-100,123,124"
|
||||
func Range(expr string, handle func(val int)) error {
|
||||
for _, item := range strings.Split(expr, ",") {
|
||||
item = strings.TrimSpace(item)
|
||||
if item == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// is range, eg: "1-100", "-20-2"
|
||||
if idx := checkfn.IndexByteAfter(item, '-', 1); idx > 0 {
|
||||
start, end, err := parseIntRange(item, idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// range number
|
||||
for i := start; i <= end; i++ {
|
||||
handle(i)
|
||||
}
|
||||
} else {
|
||||
iVal, err := strconv.Atoi(item)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid integer value: %q", item)
|
||||
}
|
||||
handle(iVal)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Expand a number range expression to int[]. eg: "1-100,123,124"
|
||||
func Expand(expr string) ([]int, error) {
|
||||
var nums []int
|
||||
for _, item := range strings.Split(expr, ",") {
|
||||
if item == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// is range, eg: "1-100", "-20-2"
|
||||
if idx := checkfn.IndexByteAfter(item, '-', 1); idx > 0 {
|
||||
ints, err := expandIntRange(item, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nums = append(nums, ints...)
|
||||
} else {
|
||||
iVal, err := strconv.Atoi(item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid integer value: %q", item)
|
||||
}
|
||||
nums = append(nums, iVal)
|
||||
}
|
||||
}
|
||||
return nums, nil
|
||||
}
|
||||
|
||||
// 处理范围格式
|
||||
// eg: "1-30" -> [1, 30], "-20-2" -> [-20, 2]
|
||||
func parseIntRange(value string, sepIdx int) (min int, max int, err error) {
|
||||
start, end := value[:sepIdx], value[sepIdx+1:]
|
||||
|
||||
min, err = strconv.Atoi(start)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid range start value: %q", start)
|
||||
return
|
||||
}
|
||||
|
||||
max, err = strconv.Atoi(end)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid range end value: %q", end)
|
||||
return
|
||||
}
|
||||
|
||||
// swap min and max
|
||||
if min > max {
|
||||
min, max = max, min
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 将 "1-30" 转换为 int 列表
|
||||
func expandIntRange(value string, sepIdx int) ([]int, error) {
|
||||
var ints []int
|
||||
start, end, err := parseIntRange(value, sepIdx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := start; i <= end; i++ {
|
||||
ints = append(ints, i)
|
||||
}
|
||||
return ints, nil
|
||||
}
|
||||
|
||||
19
vendor/github.com/gookit/goutil/mathutil/types.go
generated
vendored
Normal file
19
vendor/github.com/gookit/goutil/mathutil/types.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package mathutil
|
||||
|
||||
// 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) (uint, error)
|
||||
|
||||
// ToUint64Func convert value to uint
|
||||
type ToUint64Func func(any) (uint64, error)
|
||||
|
||||
// ToFloatFunc convert value to float
|
||||
type ToFloatFunc func(any) (float64, error)
|
||||
|
||||
// ToTypeFunc convert value to defined type
|
||||
type ToTypeFunc[T any] func(any) (T, error)
|
||||
6
vendor/github.com/gookit/goutil/structs/convert.go
generated
vendored
6
vendor/github.com/gookit/goutil/structs/convert.go
generated
vendored
@@ -66,11 +66,11 @@ func ToString(st any, optFns ...MapOptFunc) string {
|
||||
const defaultFieldTag = "json"
|
||||
|
||||
// CustomUserFunc for map convert
|
||||
// - fName: raw field name in struct
|
||||
// - fName: raw field name in struct
|
||||
//
|
||||
// Returns:
|
||||
// - ok: return true to collect field, otherwise excluded.
|
||||
// - newVal: `newVal != nil` return new value to collect, otherwise collect original value.
|
||||
// - ok: return true to collect field, otherwise excluded.
|
||||
// - newVal: `newVal != nil` return new value to collect, otherwise collect original value.
|
||||
type CustomUserFunc func(fName string, fv reflect.Value) (ok bool, newVal any)
|
||||
|
||||
// MapOptions for convert struct to map
|
||||
|
||||
162
vendor/github.com/gookit/goutil/strutil/check.go
generated
vendored
162
vendor/github.com/gookit/goutil/strutil/check.go
generated
vendored
@@ -3,6 +3,7 @@ package strutil
|
||||
import (
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
@@ -17,18 +18,43 @@ var IsHttpURL = checkfn.IsHttpURL
|
||||
// IsNumChar returns true if the given character is a numeric, otherwise false.
|
||||
func IsNumChar(c byte) bool { return c >= '0' && c <= '9' }
|
||||
|
||||
var intReg = regexp.MustCompile(`^\d+$`)
|
||||
var floatReg = regexp.MustCompile(`^[-+]?\d*\.?\d+$`)
|
||||
var (
|
||||
uintReg = regexp.MustCompile(`^\d+$`)
|
||||
intReg = regexp.MustCompile(`^[-+]?\d+$`)
|
||||
|
||||
floatReg = regexp.MustCompile(`^[-+]?\d*\.?\d+$`)
|
||||
)
|
||||
|
||||
// IsInt check the string is an integer number
|
||||
func IsInt(s string) bool { return intReg.MatchString(s) }
|
||||
func IsInt(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
return intReg.MatchString(s)
|
||||
}
|
||||
|
||||
// IsUint check the string is an unsigned integer number
|
||||
func IsUint(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
return uintReg.MatchString(s)
|
||||
}
|
||||
|
||||
// IsFloat check the string is a float number
|
||||
func IsFloat(s string) bool { return floatReg.MatchString(s) }
|
||||
func IsFloat(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
return floatReg.MatchString(s)
|
||||
}
|
||||
|
||||
// IsNumeric returns true if the given string is a numeric(int/float), otherwise false.
|
||||
func IsNumeric(s string) bool { return checkfn.IsNumeric(s) }
|
||||
|
||||
// IsPositiveNum check the string is a positive number
|
||||
func IsPositiveNum(s string) bool { return checkfn.IsPositiveNum(s) }
|
||||
|
||||
// IsAlphabet char
|
||||
func IsAlphabet(char uint8) bool {
|
||||
// A 65 -> Z 90
|
||||
@@ -48,6 +74,28 @@ func IsAlphaNum(c uint8) bool {
|
||||
return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
|
||||
}
|
||||
|
||||
// IsUpper returns true if the given string is an uppercase, otherwise false.
|
||||
func IsUpper(s string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] >= 'A' && s[i] <= 'Z' {
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsLower returns true if the given string is a lowercase, otherwise false.
|
||||
func IsLower(s string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] >= 'a' && s[i] <= 'z' {
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// StrPos alias of the strings.Index
|
||||
func StrPos(s, sub string) int { return strings.Index(s, sub) }
|
||||
|
||||
@@ -68,6 +116,16 @@ func IContains(s, sub string) bool {
|
||||
// ContainsByte in given string.
|
||||
func ContainsByte(s string, c byte) bool { return strings.IndexByte(s, c) >= 0 }
|
||||
|
||||
// ContainsByteOne in given string.
|
||||
func ContainsByteOne(s string, bs []byte) bool {
|
||||
for _, b := range bs {
|
||||
if strings.IndexByte(s, b) >= 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InArray alias of HasOneSub()
|
||||
var InArray = HasOneSub
|
||||
|
||||
@@ -95,10 +153,10 @@ func IContainsOne(s string, subs []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ContainsAll substr(s) in the given string. alias of HasAllSubs()
|
||||
// ContainsAll given string should contain all substrings. alias of HasAllSubs()
|
||||
func ContainsAll(s string, subs []string) bool { return HasAllSubs(s, subs) }
|
||||
|
||||
// HasAllSubs all substr in the given string.
|
||||
// HasAllSubs given string should contain all substrings
|
||||
func HasAllSubs(s string, subs []string) bool {
|
||||
for _, sub := range subs {
|
||||
if !strings.Contains(s, sub) {
|
||||
@@ -227,8 +285,12 @@ var (
|
||||
verRegex = regexp.MustCompile(`^[0-9][\d.]+(-\w+)?$`)
|
||||
// regex for check variable name
|
||||
varRegex = regexp.MustCompile(`^[a-zA-Z][\w-]*$`)
|
||||
// regex for check env var name
|
||||
envRegex = regexp.MustCompile(`^[A-Z][A-Z0-9_]*$`)
|
||||
// IsVariableName alias for IsVarName
|
||||
IsVariableName = IsVarName
|
||||
// regex for check uuid string. format: 8-4-4-4-12
|
||||
uuidPattern = regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`)
|
||||
)
|
||||
|
||||
// IsVersion number. eg: 1.2.0
|
||||
@@ -237,27 +299,95 @@ func IsVersion(s string) bool { return verRegex.MatchString(s) }
|
||||
// IsVarName is valid variable name.
|
||||
func IsVarName(s string) bool { return varRegex.MatchString(s) }
|
||||
|
||||
// Compare for two strings.
|
||||
func Compare(s1, s2, op string) bool { return VersionCompare(s1, s2, op) }
|
||||
// IsEnvName is valid ENV var name. eg: APP_NAME
|
||||
func IsEnvName(s string) bool { return envRegex.MatchString(s) }
|
||||
|
||||
// VersionCompare for two version strings.
|
||||
func VersionCompare(v1, v2, op string) bool {
|
||||
// IsUUID check if the string is a valid UUID format.
|
||||
func IsUUID(s string) bool { return uuidPattern.MatchString(s) }
|
||||
|
||||
// Compare for two strings.
|
||||
func Compare(s1, s2, op string) bool {
|
||||
switch op {
|
||||
case ">", "gt":
|
||||
return v1 > v2
|
||||
return s1 > s2
|
||||
case "<", "lt":
|
||||
return v1 < v2
|
||||
return s1 < s2
|
||||
case ">=", "gte":
|
||||
return v1 >= v2
|
||||
return s1 >= s2
|
||||
case "<=", "lte":
|
||||
return v1 <= v2
|
||||
return s1 <= s2
|
||||
case "!=", "ne", "neq":
|
||||
return v1 != v2
|
||||
return s1 != s2
|
||||
default: // eq
|
||||
return v1 == v2
|
||||
return s1 == s2
|
||||
}
|
||||
}
|
||||
|
||||
// VersionCompare for two version strings. eg: 1.2.0 > 1.1.0
|
||||
func VersionCompare(v1, v2, op string) bool {
|
||||
parts1 := parseVersion(v1)
|
||||
parts2 := parseVersion(v2)
|
||||
|
||||
result := compareVersions(parts1, parts2)
|
||||
switch op {
|
||||
case ">", "gt":
|
||||
return result > 0
|
||||
case "<", "lt":
|
||||
return result < 0
|
||||
case "=", "==", "eq":
|
||||
return result == 0
|
||||
case "!=", "ne", "neq":
|
||||
return result != 0
|
||||
case ">=", "gte":
|
||||
return result >= 0
|
||||
case "<=", "lte":
|
||||
return result <= 0
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// parseVersion 将版本号字符串解析为整数数组
|
||||
func parseVersion(version string) []int {
|
||||
parts := strings.Split(version, ".")
|
||||
result := make([]int, len(parts))
|
||||
|
||||
for i, part := range parts {
|
||||
num, _ := strconv.Atoi(part)
|
||||
result[i] = num
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// compareVersions 比较两个版本号数组
|
||||
// 返回: -1 表示 v1 < v2, 0 表示 v1 = v2, 1 表示 v1 > v2
|
||||
func compareVersions(v1, v2 []int) int {
|
||||
maxLen := len(v1)
|
||||
if len(v2) > maxLen {
|
||||
maxLen = len(v2)
|
||||
}
|
||||
|
||||
for i := 0; i < maxLen; i++ {
|
||||
num1 := 0
|
||||
if i < len(v1) {
|
||||
num1 = v1[i]
|
||||
}
|
||||
|
||||
num2 := 0
|
||||
if i < len(v2) {
|
||||
num2 = v2[i]
|
||||
}
|
||||
|
||||
if num1 > num2 {
|
||||
return 1
|
||||
} else if num1 < num2 {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// SimpleMatch all substring in the give text string.
|
||||
//
|
||||
// Difference the ContainsAll:
|
||||
|
||||
36
vendor/github.com/gookit/goutil/strutil/convbase.go
generated
vendored
36
vendor/github.com/gookit/goutil/strutil/convbase.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package strutil
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -16,6 +17,7 @@ const (
|
||||
Base16Chars = "0123456789abcdef"
|
||||
Base32Chars = "0123456789abcdefghjkmnpqrstvwxyz"
|
||||
Base36Chars = "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||
Base48Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL"
|
||||
Base62Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
Base64Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
|
||||
)
|
||||
@@ -33,14 +35,36 @@ func Base10Conv(src string, to int) string { return BaseConv(src, 10, to) }
|
||||
// BaseConv("7b", 16, 10) // Output: "123"
|
||||
func BaseConv(src string, from, to int) string {
|
||||
if from > 64 || from < 2 {
|
||||
return ""
|
||||
from = 10
|
||||
}
|
||||
if to > 64 || to < 2 {
|
||||
return ""
|
||||
to = 16
|
||||
}
|
||||
return BaseConvByTpl(src, Base64Chars[:from], Base64Chars[:to])
|
||||
}
|
||||
|
||||
// BaseConvInt convert base int to new base string.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// BaseConv(123, 16) // Output: "7b"
|
||||
func BaseConvInt(src uint64, toBase int) string {
|
||||
if toBase > 64 || toBase < 2 {
|
||||
toBase = 16
|
||||
}
|
||||
|
||||
// bigInt 支持 2-62 进制转换处理 TODO
|
||||
if toBase <= 36 {
|
||||
return strconv.FormatUint(src, toBase)
|
||||
}
|
||||
if toBase <= 62 {
|
||||
bigInt := new(big.Int).SetUint64(src)
|
||||
return bigInt.Text(toBase)
|
||||
}
|
||||
|
||||
return BaseConvIntByTpl(src, Base64Chars[:toBase])
|
||||
}
|
||||
|
||||
// BaseConvByTpl convert base string by template.
|
||||
//
|
||||
// Usage:
|
||||
@@ -58,7 +82,7 @@ func BaseConvByTpl(src string, fromBase, toBase string) string {
|
||||
var err error
|
||||
dec, err = strconv.ParseUint(src, 10, 0)
|
||||
if err != nil {
|
||||
basefn.Panicf("input is not a valid decimal number: %s", src)
|
||||
basefn.Panicf("input is not a valid decimal number: %s(%v)", src, err)
|
||||
}
|
||||
} else {
|
||||
fLen := uint64(len(fromBase))
|
||||
@@ -67,6 +91,12 @@ func BaseConvByTpl(src string, fromBase, toBase string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// convert to new base
|
||||
return BaseConvIntByTpl(dec, toBase)
|
||||
}
|
||||
|
||||
// BaseConvIntByTpl convert base int to new base string.
|
||||
func BaseConvIntByTpl(dec uint64, toBase string) string {
|
||||
// convert to new base
|
||||
var res string
|
||||
toLen := uint64(len(toBase))
|
||||
|
||||
21
vendor/github.com/gookit/goutil/strutil/convert.go
generated
vendored
21
vendor/github.com/gookit/goutil/strutil/convert.go
generated
vendored
@@ -88,7 +88,7 @@ func JoinAny(sep string, parts ...any) string {
|
||||
func Implode(sep string, ss ...string) string { return strings.Join(ss, sep) }
|
||||
|
||||
/*************************************************************
|
||||
* convert value to string
|
||||
* region value to string
|
||||
*************************************************************/
|
||||
|
||||
// String convert value to string, return error on failed
|
||||
@@ -144,7 +144,7 @@ func AnyToString(val any, defaultAsErr bool) (s string, err error) {
|
||||
if !defaultAsErr {
|
||||
optFn = comfunc.WithUserConvFn(comfunc.StrBySprintFn)
|
||||
}
|
||||
return ToStringWith(val, optFn)
|
||||
return comfunc.ToStringWith(val, optFn)
|
||||
}
|
||||
|
||||
// ToStringWith try to convert value to string. can with some option func, more see comfunc.ConvOption.
|
||||
@@ -153,7 +153,7 @@ func ToStringWith(in any, optFns ...comfunc.ConvOptionFn) (string, error) {
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert string value to bool
|
||||
* region string value to bool
|
||||
*************************************************************/
|
||||
|
||||
// ToBool convert string to bool
|
||||
@@ -185,7 +185,7 @@ func Bool(s string) (bool, error) {
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert string value to int
|
||||
* region string value to int
|
||||
*************************************************************/
|
||||
|
||||
// Int convert string to int, alias of ToInt()
|
||||
@@ -234,7 +234,7 @@ func IntOrPanic(s string) int {
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert string value to int64
|
||||
* region convert string to int64
|
||||
*************************************************************/
|
||||
|
||||
// Int64 convert string to int, will ignore error
|
||||
@@ -286,7 +286,7 @@ func Int64OrPanic(s string) int64 {
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert string value to uint
|
||||
* region string value to uint
|
||||
*************************************************************/
|
||||
|
||||
// Uint convert string to uint, will ignore error
|
||||
@@ -335,7 +335,7 @@ func UintOr(s string, defVal uint64) uint64 {
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert string value to byte
|
||||
* region string value to byte
|
||||
* refer from https://github.com/valyala/fastjson/blob/master/util.go
|
||||
*************************************************************/
|
||||
|
||||
@@ -361,7 +361,7 @@ func ToBytes(s string) (b []byte) {
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert string value to int/string slice, time.Time
|
||||
* region string to int/string slice, time.Time
|
||||
*************************************************************/
|
||||
|
||||
// Ints alias of the ToIntSlice(). default sep is comma(,)
|
||||
@@ -406,11 +406,6 @@ func ToSlice(s string, sep ...string) []string {
|
||||
return Split(s, ",")
|
||||
}
|
||||
|
||||
// ToOSArgs split string to string[](such as os.Args)
|
||||
// func ToOSArgs(s string) []string {
|
||||
// return cliutil.StringToOSArgs(s) // error: import cycle not allowed
|
||||
// }
|
||||
|
||||
// ToDuration parses a duration string. such as "300ms", "-1.5h" or "2h45m".
|
||||
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
||||
func ToDuration(s string) (time.Duration, error) {
|
||||
|
||||
50
vendor/github.com/gookit/goutil/strutil/format.go
generated
vendored
50
vendor/github.com/gookit/goutil/strutil/format.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package strutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
@@ -184,3 +185,52 @@ func IndentBytes(b, prefix []byte) []byte {
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Replaces replace multi strings
|
||||
//
|
||||
// pairs: {old1: new1, old2: new2, ...}
|
||||
//
|
||||
// Can also use:
|
||||
//
|
||||
// strings.NewReplacer("old1", "new1", "old2", "new2").Replace(str)
|
||||
func Replaces(str string, pairs map[string]string) string {
|
||||
return NewReplacer(pairs).Replace(str)
|
||||
}
|
||||
|
||||
// ReplaceVars replaces simple variables in a string. format: {varName}
|
||||
//
|
||||
// Usage:
|
||||
// strutil.ReplaceVars("{name}, age is {age}", map[string]string{
|
||||
// "name": "Joe",
|
||||
// "age": "18"
|
||||
// })
|
||||
func ReplaceVars(s string, vars map[string]string) string {
|
||||
if !ContainsByte(s, '{') {
|
||||
return s
|
||||
}
|
||||
|
||||
// format var name to {name}
|
||||
pairs := make(map[string]string)
|
||||
for k, v := range vars {
|
||||
vName := "{" + k + "}"
|
||||
pairs[vName] = v
|
||||
}
|
||||
return NewReplacer(pairs).Replace(s)
|
||||
}
|
||||
|
||||
// NewReplacer instance
|
||||
func NewReplacer(pairs map[string]string) *strings.Replacer {
|
||||
ss := make([]string, len(pairs)*2)
|
||||
for old, newVal := range pairs {
|
||||
ss = append(ss, old, newVal)
|
||||
}
|
||||
return strings.NewReplacer(ss...)
|
||||
}
|
||||
|
||||
// WrapTag for given string.
|
||||
func WrapTag(s, tag string) string {
|
||||
if s == "" {
|
||||
return s
|
||||
}
|
||||
return fmt.Sprintf("<%s>%s</%s>", tag, s, tag)
|
||||
}
|
||||
|
||||
206
vendor/github.com/gookit/goutil/strutil/gensn.go
generated
vendored
206
vendor/github.com/gookit/goutil/strutil/gensn.go
generated
vendored
@@ -1,13 +1,15 @@
|
||||
package strutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"math/rand"
|
||||
"math/rand" // TODO use v2 on 1.22+
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/gookit/goutil/mathutil"
|
||||
"github.com/gookit/goutil/x/basefn"
|
||||
)
|
||||
|
||||
@@ -34,12 +36,12 @@ func MicroTimeID() string { return MTimeBaseID(10) }
|
||||
|
||||
// MicroTimeHexID micro time HEX ID generate.
|
||||
//
|
||||
// return like: 5b5f0588af1761ad3(len: 16-17)
|
||||
// return like: 643d4cec7db9e(len: 13)
|
||||
func MicroTimeHexID() string { return MTimeHexID() }
|
||||
|
||||
// MTimeHexID micro time HEX ID generate.
|
||||
//
|
||||
// return like: 5b5f0588af1761ad3(len: 16-17)
|
||||
// return like: 643d4cec7db9e(len: 13)
|
||||
func MTimeHexID() string { return MTimeBaseID(16) }
|
||||
|
||||
// MTimeBase36 micro time BASE36 id generate.
|
||||
@@ -48,12 +50,19 @@ func MTimeBase36() string { return MTimeBaseID(36) }
|
||||
// MTimeBaseID micro time BASE id generate. toBase: 2-36
|
||||
//
|
||||
// Examples:
|
||||
// - MTimeBaseID(16): 5b5f0588af1761ad3(len: 16-17)
|
||||
// - MTimeBaseID(36): gorntzvsa73mo(len: 13)
|
||||
// - toBase=16: 643d4cec7db9e(len: 13)
|
||||
// - toBase=36: hd312z9ka2(len: 10)
|
||||
func MTimeBaseID(toBase int) string {
|
||||
// eg: 1763431181849557
|
||||
ms := time.Now().UnixMicro()
|
||||
ri := mathutil.RandomInt(DefMinInt, DefMaxInt)
|
||||
return strconv.FormatInt(ms, toBase) + strconv.FormatInt(int64(ri), toBase)
|
||||
// rand 1000 - 9999
|
||||
// ri := mathutil.RandomInt(DefMinInt, DefMaxInt)
|
||||
ri := 1000 + rand.Int63n(8999)
|
||||
|
||||
if toBase > 36 {
|
||||
return BaseConvInt(uint64(ms)+uint64(ri), toBase)
|
||||
}
|
||||
return strconv.FormatInt(ms+ri, toBase)
|
||||
}
|
||||
|
||||
// DatetimeNo generate. can use for order-no.
|
||||
@@ -84,20 +93,144 @@ func DateSN(prefix string) string {
|
||||
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)
|
||||
// rs := rand.New(rand.NewSource(nt.UnixNano()))
|
||||
bs = strconv.AppendInt(bs, 1000+rand.Int63n(8999), 10)
|
||||
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
// DateSNV2 generate date serial number.
|
||||
// DateSNOpt 基于时间生成唯一编号
|
||||
type DateSNOpt struct {
|
||||
Layout string // time layout
|
||||
// RandMax int // rand max
|
||||
DateLen int // 时间格式长度,后面部分将会进行进制转换 默认 8(yyyyMMdd)
|
||||
ConvBase int // DateLen 之后的转换 base 2-64. default 36
|
||||
// EnableSeq bool // 需要高并发生成时可以启用自增序号。默认不启用
|
||||
SeqMaxVal int // 自增序号最大值,之后后自动重置
|
||||
globalSeq int64 // 自增,确保同一时刻生成的编号不重复. EnableSeq=true 时启用
|
||||
}
|
||||
|
||||
// default setting: {时间年到秒14位}
|
||||
var defOpt = NewDateSNOpt()
|
||||
|
||||
// ConfigSNOpt config default date sn option
|
||||
func ConfigSNOpt(fn func(opt *DateSNOpt)) {
|
||||
fn(defOpt)
|
||||
}
|
||||
|
||||
// NewDateSNOpt create a new DateSNOpt instance.
|
||||
func NewDateSNOpt() *DateSNOpt {
|
||||
return &DateSNOpt{
|
||||
Layout: "20060102150405.000000",
|
||||
// RandMax: 8999,
|
||||
DateLen: 8,
|
||||
ConvBase: 36,
|
||||
// EnableSeq: true,
|
||||
SeqMaxVal: 8999,
|
||||
}
|
||||
}
|
||||
|
||||
// prepare for generate
|
||||
func (do *DateSNOpt) prepare() {
|
||||
if do.DateLen <= 0 {
|
||||
do.DateLen = 8 // default 8 for yyyyMMdd
|
||||
}
|
||||
if do.ConvBase <= 0 {
|
||||
do.ConvBase = 36
|
||||
}
|
||||
if do.Layout == "" {
|
||||
do.Layout = "20060102150405.000000"
|
||||
}
|
||||
// get sequence max value (default 9999)
|
||||
if do.SeqMaxVal <= 0 {
|
||||
do.SeqMaxVal = 8999
|
||||
}
|
||||
}
|
||||
|
||||
func (do *DateSNOpt) getSeqValue() int64 {
|
||||
// use atomic sequence for guaranteed uniqueness (even without EnableSeq)
|
||||
// this ensures no collisions in tight loops
|
||||
seq := atomic.AddInt64(&do.globalSeq, 1)
|
||||
|
||||
// auto reset when seq exceeds SeqMaxVal (thread-safe using CAS)
|
||||
if seq > int64(do.SeqMaxVal) {
|
||||
// try to reset to 1, other goroutines may have already done it
|
||||
atomic.CompareAndSwapInt64(&do.globalSeq, seq, 1)
|
||||
seq = seq % int64(do.SeqMaxVal)
|
||||
if seq == 0 {
|
||||
seq = 1
|
||||
}
|
||||
}
|
||||
return 1000 + seq
|
||||
}
|
||||
|
||||
// GenSN generate date serial number.
|
||||
func (do *DateSNOpt) GenSN(prefix string) string {
|
||||
pl := len(prefix)
|
||||
bs := make([]byte, 0, 22+pl)
|
||||
if pl > 0 {
|
||||
bs = append(bs, prefix...)
|
||||
}
|
||||
do.prepare()
|
||||
|
||||
// get time and format
|
||||
nt := time.Now()
|
||||
bs = nt.AppendFormat(bs, do.Layout)
|
||||
|
||||
// remove the dot separator if exists
|
||||
dotIdx := -1
|
||||
for i := pl; i < len(bs); i++ {
|
||||
if bs[i] == '.' {
|
||||
dotIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if dotIdx > 0 {
|
||||
bs = append(bs[:dotIdx], bs[dotIdx+1:]...)
|
||||
}
|
||||
|
||||
// determine date length (default 8 for yyyyMMdd)
|
||||
idx := do.DateLen + pl
|
||||
// high concurrency mode: sequence is the main differentiator
|
||||
extBs := strconv.AppendInt(bs[idx:], do.getSeqValue(), 10)
|
||||
if extBs[0] == '0' {
|
||||
extBs[0] = '1'
|
||||
}
|
||||
extInt := SafeUint(string(extBs))
|
||||
|
||||
// convert extension to target base
|
||||
bs = append(bs[:idx], BaseConvInt(extInt, do.ConvBase)...)
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
// 确保同一时刻生成的编号不重复 max: 89999
|
||||
var globalSeqSnV2 int64 = 0
|
||||
|
||||
func getSeqValue() int64 {
|
||||
// use atomic sequence for guaranteed uniqueness (even without EnableSeq)
|
||||
// this ensures no collisions in tight loops
|
||||
seq := atomic.AddInt64(&globalSeqSnV2, 1)
|
||||
|
||||
// auto reset when seq exceeds SeqMaxVal (thread-safe using CAS)
|
||||
if seq > 89999 {
|
||||
// try to reset to 1, other goroutines may have already done it
|
||||
atomic.CompareAndSwapInt64(&globalSeqSnV2, seq, 1)
|
||||
seq = seq % 89999
|
||||
if seq == 0 {
|
||||
seq = 1
|
||||
}
|
||||
}
|
||||
return seq
|
||||
}
|
||||
|
||||
// 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 {
|
||||
func DateSNv2(prefix string, extBase ...int) string {
|
||||
pl := len(prefix)
|
||||
bs := make([]byte, 0, 22+pl)
|
||||
if pl > 0 {
|
||||
@@ -108,14 +241,51 @@ func DateSNV2(prefix string, extBase ...int) string {
|
||||
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)
|
||||
// 6bit micro + 5bit rand 10000 - 99999
|
||||
// ext := strconv.AppendInt(bs[16+pl:], 10000+rand.Int63n(89999), 10)
|
||||
ext := strconv.AppendInt(bs[16+pl:], 10000+getSeqValue(), 10)
|
||||
// prefix + yyyyMMddHHmmss + ext(convert to base)
|
||||
base := basefn.FirstOr(extBase, 36)
|
||||
bs = append(bs[:14+pl], strconv.FormatInt(SafeInt64(string(ext)), base)...)
|
||||
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
var (
|
||||
// key is dateLen + extBase
|
||||
dsoMap = make(map[string]*DateSNOpt)
|
||||
dsoMutex sync.RWMutex
|
||||
)
|
||||
|
||||
// DateSNv3 generate date serial number.
|
||||
// - 2 < extBase <= 64
|
||||
// - return: PREFIX + DATETIME(yyyyMMddHHmmss).dateLen + extBase(DATETIME.after+6bit micro + 5bit random number)
|
||||
// - dateLen: 为 DATETIME(yyyyMMddHHmmss) 保留的长度,默认为 8(yyyyMMdd) 后面的给 extBase 使用
|
||||
//
|
||||
// Example:
|
||||
// - prefix=P, dateLen=8, extBase=16, return: P202511139vs99gbifnj len: 20
|
||||
// - prefix=P, dateLen=6, extBase=36, return: P2025119yn52qhefati len: 19
|
||||
// - prefix=P, dateLen=6, extBase=48, return: P202511k9ksgD1fe6x len: 18
|
||||
// - prefix=P, dateLen=4, extBase=62, return: P2025aZl8N0y58M7 len: 16
|
||||
func DateSNv3(prefix string, dateLen int, extBase ...int) string {
|
||||
baseVal := basefn.FirstOr(extBase, 36)
|
||||
cacheKey := fmt.Sprintf("%d%d", dateLen, baseVal)
|
||||
|
||||
dsoMutex.RLock()
|
||||
dso, ok := dsoMap[cacheKey]
|
||||
dsoMutex.RUnlock()
|
||||
|
||||
if !ok {
|
||||
dsoMutex.Lock()
|
||||
// double check,防止在加锁期间其他 goroutine 已经创建
|
||||
if dso, ok = dsoMap[cacheKey]; !ok {
|
||||
dso = NewDateSNOpt()
|
||||
// dso.EnableSeq = true
|
||||
dso.DateLen = dateLen
|
||||
dso.ConvBase = baseVal
|
||||
dsoMap[cacheKey] = dso
|
||||
}
|
||||
dsoMutex.Unlock()
|
||||
}
|
||||
return dso.GenSN(prefix)
|
||||
}
|
||||
|
||||
31
vendor/github.com/gookit/goutil/strutil/hash.go
generated
vendored
31
vendor/github.com/gookit/goutil/strutil/hash.go
generated
vendored
@@ -2,8 +2,10 @@ package strutil
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
@@ -64,6 +66,33 @@ func Md5Bytes(src any) []byte { return byteutil.Md5(src) }
|
||||
// ShortMd5 Generate a 16-bit md5 string. remove the first 8 and last 8 bytes from 32-bit md5 string.
|
||||
func ShortMd5(src any) string { return string(byteutil.ShortMd5(src)) }
|
||||
|
||||
//
|
||||
// ----------------------- Simple UUID -----------------------------
|
||||
//
|
||||
|
||||
// UUIDv4 Generate a simple UUIDv4 string
|
||||
func UUIDv4() (string, error) {
|
||||
b := make([]byte, 16)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return "", fmt.Errorf("generate UUID fail: %w", err)
|
||||
}
|
||||
|
||||
// 设置版本(4)和变体
|
||||
b[6] = (b[6] & 0x0f) | 0x40 // Version 4
|
||||
b[8] = (b[8] & 0x3f) | 0x80 // Variant 10
|
||||
|
||||
return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:16]), nil
|
||||
}
|
||||
|
||||
// ShortUUID Generate a short UUID (8 characters)
|
||||
func ShortUUID() string {
|
||||
b := make([]byte, 4)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return fmt.Sprintf("%04x", b)
|
||||
}
|
||||
return fmt.Sprintf("%08x", b)
|
||||
}
|
||||
|
||||
//
|
||||
// ----------------------- hash password -----------------------------
|
||||
//
|
||||
@@ -78,7 +107,7 @@ func HashPasswd(pwd, key string) string {
|
||||
|
||||
// VerifyPasswd for quick verify input password is valid
|
||||
//
|
||||
// - pwdMAC from db or config, generated by EncryptPasswd()
|
||||
// - pwdMAC from db or config, generated by HashPasswd()
|
||||
func VerifyPasswd(pwdMAC, pwd, key string) bool {
|
||||
decBts, err := hex.DecodeString(pwdMAC)
|
||||
if err != nil {
|
||||
|
||||
119
vendor/github.com/gookit/goutil/strutil/padding.go
generated
vendored
119
vendor/github.com/gookit/goutil/strutil/padding.go
generated
vendored
@@ -1,43 +1,59 @@
|
||||
package strutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
)
|
||||
|
||||
// PosFlag type
|
||||
type PosFlag uint8
|
||||
type PosFlag = comdef.Position
|
||||
|
||||
// Position for padding/resize string
|
||||
const (
|
||||
PosLeft PosFlag = iota
|
||||
PosRight
|
||||
PosMiddle
|
||||
PosRight
|
||||
PosAuto
|
||||
)
|
||||
|
||||
/*************************************************************
|
||||
* String padding operation
|
||||
*************************************************************/
|
||||
|
||||
// Padding a string.
|
||||
func Padding(s, pad string, length int, pos PosFlag) string {
|
||||
diff := len(s) - length
|
||||
// Padding Fill the string to the specified length.
|
||||
//
|
||||
// params:
|
||||
// - s: 原始字符串
|
||||
// - pad: 用于填充的字符或字符串
|
||||
// - length: 目标长度
|
||||
// - padPos: 填充位置标志(左填充或右填充)
|
||||
func Padding(s, pad string, length int, padPos PosFlag) string {
|
||||
return padding(s, pad, len(s), length, padPos)
|
||||
}
|
||||
|
||||
// Utf8Padding Fill the string to the specified length. use utf8 width.
|
||||
func Utf8Padding(s, pad string, wantLen int, padPos PosFlag) string {
|
||||
return padding(s, pad, Utf8Width(s), wantLen, padPos)
|
||||
}
|
||||
|
||||
func padding(s, pad string, sLen, wantLen int, padPos PosFlag) string {
|
||||
diff := sLen - wantLen
|
||||
if diff >= 0 { // do not need padding.
|
||||
return s
|
||||
}
|
||||
|
||||
if pad == "" || pad == " " {
|
||||
mark := ""
|
||||
if pos == PosRight { // to right
|
||||
mark = "-"
|
||||
// pad space.
|
||||
if len(s) == sLen && (pad == "" || pad == " ") {
|
||||
// Sprintf: 是按字数来填充的,不管中英文都是一个字符 - 有问题
|
||||
if padPos == PosRight { // to right
|
||||
return s + strings.Repeat(" ", -diff)
|
||||
}
|
||||
|
||||
// padding left: "%7s", padding right: "%-7s"
|
||||
tpl := fmt.Sprintf("%s%d", mark, length)
|
||||
return fmt.Sprintf(`%`+tpl+`s`, s)
|
||||
return strings.Repeat(" ", -diff) + s
|
||||
}
|
||||
|
||||
if pos == PosRight { // to right
|
||||
// other character.
|
||||
if padPos == PosRight { // to right
|
||||
return s + Repeat(pad, -diff)
|
||||
}
|
||||
return Repeat(pad, -diff) + s
|
||||
@@ -53,26 +69,6 @@ func PadRight(s, pad string, length int) string {
|
||||
return Padding(s, pad, length, PosRight)
|
||||
}
|
||||
|
||||
// Resize a string by given length and align settings. padding space.
|
||||
func Resize(s string, length int, align PosFlag) string {
|
||||
diff := len(s) - length
|
||||
if diff >= 0 { // do not need padding.
|
||||
return s
|
||||
}
|
||||
|
||||
if align == PosMiddle {
|
||||
padLn := (length - len(s)) / 2
|
||||
if diff := length - padLn*2; diff > 0 {
|
||||
s += " "
|
||||
}
|
||||
|
||||
padStr := string(RepeatBytes(' ', padLn))
|
||||
return padStr + s + padStr
|
||||
}
|
||||
|
||||
return Padding(s, " ", length, align)
|
||||
}
|
||||
|
||||
// PadChars padding a rune/byte to want length and with position flag
|
||||
func PadChars[T byte | rune](cs []T, pad T, length int, pos PosFlag) []T {
|
||||
ln := len(cs)
|
||||
@@ -130,6 +126,59 @@ func PadRunesRight(rs []rune, pad rune, length int) []rune {
|
||||
return PadChars(rs, pad, length, PosRight)
|
||||
}
|
||||
|
||||
// Align a string by given length and align settings. alias of Resize
|
||||
func Align(s string, length int, align comdef.Align) string {
|
||||
return resize(s, len(s), length, align, false)
|
||||
}
|
||||
|
||||
// Utf8Align a string by given length and align settings. alias of Utf8Resize
|
||||
func Utf8Align(s string, length int, align comdef.Align) string {
|
||||
return resize(s, Utf8Width(s), length, align, false)
|
||||
}
|
||||
|
||||
// Resize a string by given length and align settings. use padding space.
|
||||
// If len(s) > wantLen, will truncate it.
|
||||
func Resize(s string, length int, align comdef.Align) string {
|
||||
return resize(s, len(s), length, align, true)
|
||||
}
|
||||
|
||||
// Utf8Resize a string by given length and align settings. use padding space.
|
||||
// If width(s) > wantLen, will truncate it.
|
||||
func Utf8Resize(s string, length int, align comdef.Align) string {
|
||||
return resize(s, Utf8Width(s), length, align, true)
|
||||
}
|
||||
|
||||
// resize a string by given length and align settings. use padding space.
|
||||
func resize(s string, sLen, wantLen int, align comdef.Align, cutOverflow bool) string {
|
||||
diff := sLen - wantLen
|
||||
if diff >= 0 { // do not need padding.
|
||||
// cutOverflow: truncate on sLen > wantLen
|
||||
if cutOverflow && sLen > wantLen {
|
||||
if len(s) == sLen {
|
||||
return s[:wantLen]
|
||||
}
|
||||
return utf8Truncate(s, sLen, wantLen, "")
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
if align == comdef.Center {
|
||||
padLn := (wantLen - sLen) / 2
|
||||
if diff = wantLen - padLn*2; diff > 0 {
|
||||
s += " "
|
||||
}
|
||||
padStr := string(RepeatBytes(' ', padLn))
|
||||
return padStr + s + padStr
|
||||
}
|
||||
|
||||
padStr := string(RepeatBytes(' ', wantLen-sLen))
|
||||
// tip: 左对齐 - 使用空白填充右边
|
||||
if align == comdef.Left || align == comdef.PosAuto {
|
||||
return s + padStr
|
||||
}
|
||||
return padStr + s
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* String repeat operation
|
||||
*************************************************************/
|
||||
|
||||
8
vendor/github.com/gookit/goutil/strutil/parse.go
generated
vendored
8
vendor/github.com/gookit/goutil/strutil/parse.go
generated
vendored
@@ -2,6 +2,7 @@ package strutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -10,6 +11,13 @@ import (
|
||||
"github.com/gookit/goutil/byteutil"
|
||||
)
|
||||
|
||||
var regNumVersion = regexp.MustCompile(`[0-9][\d.]+([_-]\d+)?`)
|
||||
|
||||
// NumVersion parse input string, get valid number version. eg: go-1.22.3 -> 1.22.3
|
||||
func NumVersion(s string) string {
|
||||
return regNumVersion.FindString(s)
|
||||
}
|
||||
|
||||
// MustToTime convert date string to time.Time
|
||||
func MustToTime(s string, layouts ...string) time.Time {
|
||||
t, err := ToTime(s, layouts...)
|
||||
|
||||
39
vendor/github.com/gookit/goutil/strutil/runes.go
generated
vendored
39
vendor/github.com/gookit/goutil/strutil/runes.go
generated
vendored
@@ -31,13 +31,29 @@ func IsSpaceRune(r rune) bool {
|
||||
return r <= 256 && IsSpace(byte(r)) || unicode.IsSpace(r)
|
||||
}
|
||||
|
||||
// Utf8Len count of the string
|
||||
// Utf8Len count rune of the string.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// str := "hi,你好"
|
||||
//
|
||||
// len(str) // 9
|
||||
// strutil.RunesWidth(str) // 7 一个中文字占两个字符
|
||||
// RuneCount(str) = Utf8Len(s) // 5 按字算
|
||||
func Utf8Len(s string) int { return utf8.RuneCountInString(s) }
|
||||
|
||||
// Utf8len of the string
|
||||
// Utf8len count rune of the string.
|
||||
func Utf8len(s string) int { return utf8.RuneCountInString(s) }
|
||||
|
||||
// RuneCount of the string
|
||||
// RuneCount of the string.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// str := "hi,你好"
|
||||
//
|
||||
// len(str) // 9
|
||||
// strutil.RunesWidth(str) // 7 一个中文字占两个字符
|
||||
// RuneCount(str) = utf8.RuneCountInString(s) // 5 按字算
|
||||
func RuneCount(s string) int { return len([]rune(s)) }
|
||||
|
||||
// RuneWidth of the rune.
|
||||
@@ -75,8 +91,8 @@ func Utf8Width(s string) int { return RunesWidth([]rune(s)) }
|
||||
// str := "hi,你好"
|
||||
//
|
||||
// len(str) // 9
|
||||
// strutil.Utf8Width(str) // 7
|
||||
// len([]rune(str)) = utf8.RuneCountInString(s) // 5
|
||||
// strutil.RunesWidth(str) // 7 一个中文字占两个字符
|
||||
// len([]rune(str)) = utf8.RuneCountInString(s) // 5 按字算
|
||||
func RunesWidth(rs []rune) (w int) {
|
||||
if len(rs) == 0 {
|
||||
return
|
||||
@@ -95,8 +111,11 @@ func Truncate(s string, w int, tail string) string { return Utf8Truncate(s, w, t
|
||||
func TextTruncate(s string, w int, tail string) string { return Utf8Truncate(s, w, tail) }
|
||||
|
||||
// Utf8Truncate a string with given width.
|
||||
func Utf8Truncate(s string, w int, tail string) string {
|
||||
if sw := Utf8Width(s); sw <= w {
|
||||
func Utf8Truncate(s string, w int, tail string) string { return utf8Truncate(s, Utf8Width(s), w, tail) }
|
||||
|
||||
// utf8Truncate a string with given width.
|
||||
func utf8Truncate(s string, sw, w int, tail string) string {
|
||||
if sw <= w {
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -161,10 +180,14 @@ func Utf8Split(s string, w int) []string {
|
||||
return ss
|
||||
}
|
||||
|
||||
// TextWrap a string by "\n"
|
||||
// TextWrap a string by "\n". alias of the WidthWrap()
|
||||
func TextWrap(s string, w int) string { return WidthWrap(s, w) }
|
||||
|
||||
// WidthWrap a string by "\n"
|
||||
//
|
||||
// Example:
|
||||
// s := "hello 你好, world 世界"
|
||||
// s1 := strutil.TextWrap(s, 6) // "hello \n你好, \nworld \n世界"
|
||||
func WidthWrap(s string, w int) string {
|
||||
tmpW := 0
|
||||
out := ""
|
||||
|
||||
2
vendor/github.com/gookit/goutil/strutil/split.go
generated
vendored
2
vendor/github.com/gookit/goutil/strutil/split.go
generated
vendored
@@ -148,7 +148,7 @@ func SplitByWhitespace(s string) []string {
|
||||
return whitespaceRegexp.Split(s, -1)
|
||||
}
|
||||
|
||||
// Substr for a string.
|
||||
// Substr for a string. NOTE: strLn := len(runes)
|
||||
// if length <= 0, return pos to end.
|
||||
func Substr(s string, pos, length int) string {
|
||||
runes := []rune(s)
|
||||
|
||||
29
vendor/github.com/gookit/goutil/strutil/strutil.go
generated
vendored
29
vendor/github.com/gookit/goutil/strutil/strutil.go
generated
vendored
@@ -3,7 +3,6 @@ package strutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
@@ -77,34 +76,6 @@ func Valid(ss ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Replaces replace multi strings
|
||||
//
|
||||
// pairs: {old1: new1, old2: new2, ...}
|
||||
//
|
||||
// Can also use:
|
||||
//
|
||||
// strings.NewReplacer("old1", "new1", "old2", "new2").Replace(str)
|
||||
func Replaces(str string, pairs map[string]string) string {
|
||||
return NewReplacer(pairs).Replace(str)
|
||||
}
|
||||
|
||||
// NewReplacer instance
|
||||
func NewReplacer(pairs map[string]string) *strings.Replacer {
|
||||
ss := make([]string, len(pairs)*2)
|
||||
for old, newVal := range pairs {
|
||||
ss = append(ss, old, newVal)
|
||||
}
|
||||
return strings.NewReplacer(ss...)
|
||||
}
|
||||
|
||||
// WrapTag for given string.
|
||||
func WrapTag(s, tag string) string {
|
||||
if s == "" {
|
||||
return s
|
||||
}
|
||||
return fmt.Sprintf("<%s>%s</%s>", tag, s, tag)
|
||||
}
|
||||
|
||||
// SubstrCount returns the number of times the substr substring occurs in the s string.
|
||||
// Actually, it comes from strings.Count().
|
||||
//
|
||||
|
||||
4
vendor/github.com/gookit/goutil/strutil/textutil/strvar_expr.go
generated
vendored
4
vendor/github.com/gookit/goutil/strutil/textutil/strvar_expr.go
generated
vendored
@@ -15,8 +15,8 @@ import (
|
||||
// StrVarRenderer implements like shell vars renderer
|
||||
// 简单的实现类似 php, kotlin, shell 插值变量渲染,表达式解析处理。
|
||||
//
|
||||
// - var format: $var_name, ${some_var}, ${top.sub_var}
|
||||
// - func call: ${func($var_name, 'const string')}
|
||||
// - var format: $var_name, ${some_var}, ${top.sub_var}
|
||||
// - func call: ${func($var_name, 'const string')}
|
||||
type StrVarRenderer struct {
|
||||
// global variables
|
||||
vars map[string]any
|
||||
|
||||
4
vendor/github.com/gookit/goutil/strutil/textutil/textutil.go
generated
vendored
4
vendor/github.com/gookit/goutil/strutil/textutil/textutil.go
generated
vendored
@@ -13,14 +13,14 @@ import (
|
||||
|
||||
// ReplaceVars by regex replace given tpl vars.
|
||||
//
|
||||
// If a format is empty, will use {const defaultVarFormat}
|
||||
// If a format is empty, will use {const DefaultVarFormat}
|
||||
func ReplaceVars(text string, vars map[string]any, format string) string {
|
||||
return NewVarReplacer(format).Replace(text, vars)
|
||||
}
|
||||
|
||||
// RenderSMap by regex replacement given tpl vars.
|
||||
//
|
||||
// If a format is empty, will use {const defaultVarFormat}
|
||||
// If a format is empty, will use {const DefaultVarFormat}
|
||||
func RenderSMap(text string, vars map[string]string, format string) string {
|
||||
return NewVarReplacer(format).RenderSimple(text, vars)
|
||||
}
|
||||
|
||||
21
vendor/github.com/gookit/goutil/strutil/textutil/var_replacer.go
generated
vendored
21
vendor/github.com/gookit/goutil/strutil/textutil/var_replacer.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package textutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -11,7 +12,8 @@ import (
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
const defaultVarFormat = "{{,}}"
|
||||
// DefaultVarFormat var template
|
||||
const DefaultVarFormat = "{{,}}"
|
||||
|
||||
// FallbackFn type
|
||||
type FallbackFn = func(name string) (val string, ok bool)
|
||||
@@ -28,7 +30,7 @@ type VarReplacer struct {
|
||||
//
|
||||
// eg: {name: {a: 1, b: 2}} => {name.a: 1, name.b: 2}
|
||||
flatSubs bool
|
||||
// do parse env value. default: false
|
||||
// do parse env value in var-value and tpl var-name. default: false
|
||||
parseEnv bool
|
||||
// do parse default value. default: false
|
||||
//
|
||||
@@ -46,7 +48,7 @@ type VarReplacer struct {
|
||||
RenderFn func(s string, vs map[string]string) string
|
||||
}
|
||||
|
||||
// NewVarReplacer instance.
|
||||
// NewVarReplacer instance. default format is: DefaultVarFormat
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
@@ -104,7 +106,7 @@ func (r *VarReplacer) OnNotFound(fn FallbackFn) *VarReplacer {
|
||||
|
||||
// WithFormat custom var template
|
||||
func (r *VarReplacer) WithFormat(format string) *VarReplacer {
|
||||
r.Left, r.Right = strutil.QuietCut(strutil.OrElse(format, defaultVarFormat), ",")
|
||||
r.Left, r.Right = strutil.QuietCut(strutil.OrElse(format, DefaultVarFormat), ",")
|
||||
r.Init()
|
||||
return r
|
||||
}
|
||||
@@ -183,7 +185,11 @@ func (r *VarReplacer) RenderSimple(s string, varMap map[string]string) string {
|
||||
|
||||
if r.parseEnv {
|
||||
for name, val := range varMap {
|
||||
varMap[name] = varexpr.SafeParse(val)
|
||||
if strings.Contains(val, "${") {
|
||||
varMap[name] = varexpr.SafeParse(val)
|
||||
} else {
|
||||
varMap[name] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +229,11 @@ func (r *VarReplacer) doReplace(s string, varMap map[string]string) string {
|
||||
if val, ok := varMap[name]; ok {
|
||||
return val
|
||||
}
|
||||
if r.parseEnv && strutil.IsEnvName(name) {
|
||||
if val := os.Getenv(name); val != "" {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
// has custom not found handle func
|
||||
if r.NotFound != nil {
|
||||
|
||||
11
vendor/github.com/gookit/goutil/syncs/chan.go
generated
vendored
11
vendor/github.com/gookit/goutil/syncs/chan.go
generated
vendored
@@ -1,10 +1,21 @@
|
||||
package syncs
|
||||
|
||||
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.
|
||||
//
|
||||
// if panic happen, it will be recovered and return as error
|
||||
func Go(f func() error) error {
|
||||
ch := make(chan error)
|
||||
go func() {
|
||||
// add recovery handle
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ch <- fmt.Errorf("panic recover: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
ch <- f()
|
||||
}()
|
||||
return <-ch
|
||||
|
||||
37
vendor/github.com/gookit/goutil/syncs/group.go
generated
vendored
37
vendor/github.com/gookit/goutil/syncs/group.go
generated
vendored
@@ -2,6 +2,7 @@ package syncs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
@@ -44,3 +45,39 @@ func (g *ErrGroup) Add(handlers ...func() error) {
|
||||
g.Go(handler)
|
||||
}
|
||||
}
|
||||
|
||||
// Go add a handler function. if panic occurs, will catch it and return as error
|
||||
func (g *ErrGroup) Go(fn func() error) {
|
||||
// Group.Go: 调用给定函数的新流程。
|
||||
// 第一次“离开”的调用必须在等待之前发生。它会一直阻塞,直到新 goroutine 能够被添加,而该组中活跃 goroutine 数量不超过配置限制。
|
||||
// 第一次返回非零错误的调用会取消该组的上下文,如果该组是由调用 WithContext 创建的。错误将由等待返回。
|
||||
g.Group.Go(func() (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("panic recover: %v", r)
|
||||
}
|
||||
}()
|
||||
err = fn()
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
// TryGo calls the given function in a new goroutine only if the number of
|
||||
// active goroutines in the group is currently below the configured limit.
|
||||
//
|
||||
// The return value reports whether the goroutine was started.
|
||||
//
|
||||
// If panic occurs, will catch it and return as error
|
||||
func (g *ErrGroup) TryGo(fn func() error) bool {
|
||||
// 只有当组中当前活跃的 goroutine 数量低于配置限制时,才会在新的 Goroutine 中调用该函数。
|
||||
// 返回值报告是否启动了goroutine。
|
||||
return g.Group.TryGo(func() (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("panic recover: %v", r)
|
||||
}
|
||||
}()
|
||||
err = fn()
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
75
vendor/github.com/gookit/goutil/syncs/syncs.go
generated
vendored
75
vendor/github.com/gookit/goutil/syncs/syncs.go
generated
vendored
@@ -1,9 +1,21 @@
|
||||
// Package syncs provides synchronization primitives util functions.
|
||||
package syncs
|
||||
|
||||
import "sync"
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// WaitGroup is a wrapper of sync.WaitGroup.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// wg := syncs.WaitGroup{}
|
||||
// wg.Go(func() {
|
||||
// time.Sleep(time.Second)
|
||||
// })
|
||||
// wg.Wait()
|
||||
//
|
||||
type WaitGroup struct {
|
||||
sync.WaitGroup
|
||||
}
|
||||
@@ -16,3 +28,64 @@ func (wg *WaitGroup) Go(fn func()) {
|
||||
fn()
|
||||
}()
|
||||
}
|
||||
|
||||
// ContextValue create a new context with given value
|
||||
func ContextValue(key, value any) context.Context {
|
||||
return context.WithValue(context.Background(), key, value)
|
||||
}
|
||||
|
||||
// SafeMap is a goroutine-safe map.
|
||||
type SafeMap[K comparable, V any] struct {
|
||||
mu sync.RWMutex
|
||||
data map[K]V
|
||||
}
|
||||
|
||||
// NewSafeMap create a new SafeMap instance.
|
||||
func NewSafeMap[K comparable, V any]() *SafeMap[K, V] {
|
||||
return &SafeMap[K, V]{
|
||||
data: make(map[K]V),
|
||||
}
|
||||
}
|
||||
|
||||
// Set value to map.
|
||||
func (m *SafeMap[K, V]) Set(key K, value V) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.data[key] = value
|
||||
}
|
||||
|
||||
// Get value from map.
|
||||
func (m *SafeMap[K, V]) Get(key K) (value V, ok bool) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
value, ok = m.data[key]
|
||||
return value, ok
|
||||
}
|
||||
|
||||
// Delete value from map.
|
||||
func (m *SafeMap[K, V]) Delete(key K) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
delete(m.data, key)
|
||||
}
|
||||
|
||||
// Range iterate map values.
|
||||
func (m *SafeMap[K, V]) Range(fn func(key K, value V)) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
fn(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear do clear all map values.
|
||||
func (m *SafeMap[K, V]) Clear() {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.data = make(map[K]V)
|
||||
}
|
||||
|
||||
// Len get map length.
|
||||
func (m *SafeMap[K, V]) Len() int {
|
||||
return len(m.data)
|
||||
}
|
||||
|
||||
3
vendor/github.com/gookit/goutil/sysutil/os_version_windows.go
generated
vendored
3
vendor/github.com/gookit/goutil/sysutil/os_version_windows.go
generated
vendored
@@ -43,7 +43,7 @@ func VersionInfoBySys() *OSVersionInfo {
|
||||
|
||||
// OsVersionByParse Get Windows system version information by parse string
|
||||
//
|
||||
// cmdOut eg: "Microsoft Windows [Version 10.0.22631.4391]"
|
||||
// cmdOut eg: "Microsoft Windows [Version 10.0.22631.4391]"
|
||||
func OsVersionByParse(cmdOut string) (*OSVersionInfo, error) {
|
||||
return parseOsVersionString(cmdOut)
|
||||
}
|
||||
@@ -153,4 +153,3 @@ func parseOsVersionString(out string) (*OSVersionInfo, error) {
|
||||
}
|
||||
return &ovi, nil
|
||||
}
|
||||
|
||||
|
||||
2
vendor/github.com/gookit/goutil/sysutil/sysenv.go
generated
vendored
2
vendor/github.com/gookit/goutil/sysutil/sysenv.go
generated
vendored
@@ -203,7 +203,7 @@ func SearchPath(keywords string, limit int, opts ...SearchPathOption) []string {
|
||||
// if windows, will limit with .exe, .bat, .cmd
|
||||
for _, fPath := range matches {
|
||||
fExt := filepath.Ext(fPath)
|
||||
if checkfn.StringsContains(opt.LimitExt, fExt) {
|
||||
if !checkfn.StringsContains(opt.LimitExt, fExt) {
|
||||
continue
|
||||
}
|
||||
list = append(list, fPath)
|
||||
|
||||
1
vendor/github.com/gookit/goutil/sysutil/sysutil_darwin.go
generated
vendored
1
vendor/github.com/gookit/goutil/sysutil/sysutil_darwin.go
generated
vendored
@@ -1,4 +1,5 @@
|
||||
//go:build darwin
|
||||
|
||||
package sysutil
|
||||
|
||||
import "os/exec"
|
||||
|
||||
60
vendor/github.com/gookit/goutil/sysutil/sysutil_unix.go
generated
vendored
Normal file
60
vendor/github.com/gookit/goutil/sysutil/sysutil_unix.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
//go:build freebsd || openbsd || netbsd || dragonfly
|
||||
|
||||
package sysutil
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// OsName system name. like runtime.GOOS.
|
||||
// For Unix systems, this will be the actual GOOS value (freebsd, openbsd, netbsd, dragonfly)
|
||||
var OsName = runtime.GOOS
|
||||
|
||||
// IsWin system. linux windows darwin
|
||||
func IsWin() bool { return false }
|
||||
|
||||
// IsWindows system. linux windows darwin
|
||||
func IsWindows() bool { return false }
|
||||
|
||||
// IsMac system
|
||||
func IsMac() bool { return false }
|
||||
|
||||
// IsDarwin system
|
||||
func IsDarwin() bool { return false }
|
||||
|
||||
// IsLinux system
|
||||
func IsLinux() bool { return false }
|
||||
|
||||
// There are multiple possible providers to open a browser on Unix systems
|
||||
// Similar to Linux, try xdg-open and other common browser launchers
|
||||
var openBins = []string{"xdg-open", "x-www-browser", "www-browser", "firefox", "chrome", "chromium"}
|
||||
|
||||
// OpenURL Open file or browser URL
|
||||
//
|
||||
// Mac:
|
||||
//
|
||||
// open 'https://github.com/inhere'
|
||||
//
|
||||
// Linux:
|
||||
//
|
||||
// xdg-open URL
|
||||
// x-www-browser 'https://github.com/inhere'
|
||||
//
|
||||
// Windows:
|
||||
//
|
||||
// cmd /c start https://github.com/inhere
|
||||
//
|
||||
// Unix (FreeBSD, OpenBSD, etc.):
|
||||
//
|
||||
// Try xdg-open, x-www-browser, or fallback browsers
|
||||
func OpenURL(URL string) error {
|
||||
for _, bin := range openBins {
|
||||
if _, err := exec.LookPath(bin); err == nil {
|
||||
return exec.Command(bin, URL).Run()
|
||||
}
|
||||
}
|
||||
|
||||
return &exec.Error{Name: strings.Join(openBins, ","), Err: exec.ErrNotFound}
|
||||
}
|
||||
30
vendor/github.com/gookit/goutil/x/basefn/basefn.go
generated
vendored
30
vendor/github.com/gookit/goutil/x/basefn/basefn.go
generated
vendored
@@ -4,42 +4,20 @@ package basefn
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
)
|
||||
|
||||
// Panicf format panic message use fmt.Sprintf
|
||||
func Panicf(format string, v ...any) {
|
||||
panic(fmt.Sprintf(format, v...))
|
||||
}
|
||||
func Panicf(format string, v ...any) { panic(fmt.Sprintf(format, v...)) }
|
||||
|
||||
// PanicIf if cond = true, panics with an error message
|
||||
func PanicIf(cond bool, fmtAndArgs ...any) {
|
||||
if cond {
|
||||
panic(errors.New(formatWithArgs(fmtAndArgs)))
|
||||
panic(errors.New(comfunc.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 {
|
||||
|
||||
5
vendor/github.com/gookit/goutil/x/ccolor/color_tag.go
generated
vendored
5
vendor/github.com/gookit/goutil/x/ccolor/color_tag.go
generated
vendored
@@ -4,8 +4,6 @@ import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/x/termenv"
|
||||
)
|
||||
|
||||
// output colored text like uses custom tag.
|
||||
@@ -67,6 +65,7 @@ var colorTags = map[string]string{
|
||||
"normal": "0;39", // no color
|
||||
"brown": "0;33", // #A52A2A
|
||||
"yellow": "0;33",
|
||||
"ylw": "0;33",
|
||||
"ylw0": "0;33",
|
||||
"yellowB": "1;33", // with bold
|
||||
"ylw1": "1;33",
|
||||
@@ -178,7 +177,7 @@ func ReplaceTag(str string) string { return ParseTagByEnv(str) }
|
||||
// ParseTagByEnv parse given string. will check package setting.
|
||||
func ParseTagByEnv(str string) string {
|
||||
// disable OR not support color
|
||||
if termenv.NoColor() || !termenv.IsSupportColor() {
|
||||
if shouldCleanColor() {
|
||||
return ClearTag(str)
|
||||
}
|
||||
return ParseTag(str)
|
||||
|
||||
5
vendor/github.com/gookit/goutil/x/ccolor/style.go
generated
vendored
5
vendor/github.com/gookit/goutil/x/ccolor/style.go
generated
vendored
@@ -8,8 +8,9 @@ import (
|
||||
|
||||
// String color style string. TODO
|
||||
// eg:
|
||||
// s := String("red,bold")
|
||||
// s.Println("some text message")
|
||||
//
|
||||
// s := String("red,bold")
|
||||
// s.Println("some text message")
|
||||
type String string
|
||||
|
||||
// Style for color render.
|
||||
|
||||
11
vendor/github.com/gookit/goutil/x/ccolor/util.go
generated
vendored
11
vendor/github.com/gookit/goutil/x/ccolor/util.go
generated
vendored
@@ -22,6 +22,10 @@ func ColorsToCode(colors ...Color) string {
|
||||
return strings.Join(codes, ";")
|
||||
}
|
||||
|
||||
func shouldCleanColor() bool {
|
||||
return termenv.NoColor() || !termenv.IsSupportColor()
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* render color code
|
||||
*************************************************************/
|
||||
@@ -43,7 +47,7 @@ func RenderCode(code string, args ...any) string {
|
||||
}
|
||||
|
||||
// disabled OR not support color
|
||||
if !termenv.IsSupportColor() {
|
||||
if shouldCleanColor() {
|
||||
return ClearCode(message)
|
||||
}
|
||||
|
||||
@@ -62,7 +66,7 @@ func RenderString(code string, str string) string {
|
||||
}
|
||||
|
||||
// disabled OR not support color
|
||||
if !termenv.IsSupportColor() {
|
||||
if shouldCleanColor() {
|
||||
return ClearCode(str)
|
||||
}
|
||||
|
||||
@@ -79,7 +83,7 @@ func RenderWithSpaces(code string, args ...any) string {
|
||||
}
|
||||
|
||||
// disabled OR not support color
|
||||
if !termenv.IsSupportColor() {
|
||||
if shouldCleanColor() {
|
||||
return ClearCode(msg)
|
||||
}
|
||||
return StartSet + code + "m" + msg + ResetSet
|
||||
@@ -128,4 +132,3 @@ func formatLikePrintln(args []any) (message string) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
12
vendor/github.com/gookit/goutil/x/goinfo/stack.go
generated
vendored
12
vendor/github.com/gookit/goutil/x/goinfo/stack.go
generated
vendored
@@ -124,12 +124,12 @@ type CallerFilterFunc func(file string, fc *runtime.Func) bool
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// cs := sysutil.CallersInfos(3, 2)
|
||||
// for _, ci := range cs {
|
||||
// fc := runtime.FuncForPC(pc)
|
||||
// // maybe need check fc = nil
|
||||
// fnName = fc.Name()
|
||||
// }
|
||||
// cs := sysutil.CallersInfos(3, 2)
|
||||
// for _, ci := range cs {
|
||||
// fc := runtime.FuncForPC(pc)
|
||||
// // maybe need check fc = nil
|
||||
// fnName = fc.Name()
|
||||
// }
|
||||
func CallersInfos(skip, num int, filters ...CallerFilterFunc) []*CallerInfo {
|
||||
filterLn := len(filters)
|
||||
callers := make([]*CallerInfo, 0, num)
|
||||
|
||||
5
vendor/github.com/gookit/goutil/x/stdio/stdio.go
generated
vendored
5
vendor/github.com/gookit/goutil/x/stdio/stdio.go
generated
vendored
@@ -61,6 +61,11 @@ func NewScanner(in any) *bufio.Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
// SafeClose close io.Closer, ignore error
|
||||
func SafeClose(c io.Closer) {
|
||||
_ = c.Close()
|
||||
}
|
||||
|
||||
// WriteByte to stdout, will ignore error
|
||||
func WriteByte(b byte) {
|
||||
_, _ = os.Stdout.Write([]byte{b})
|
||||
|
||||
6
vendor/github.com/gookit/goutil/x/termenv/detect_nonwin.go
generated
vendored
6
vendor/github.com/gookit/goutil/x/termenv/detect_nonwin.go
generated
vendored
@@ -41,6 +41,6 @@ func detectSpecialTermColor(termVal string) (ColorLevel, bool) {
|
||||
return TermColor16, false
|
||||
}
|
||||
|
||||
func syscallStdinFd() int {
|
||||
return syscall.Stdin
|
||||
}
|
||||
func syscallStdinFd() int { return syscall.Stdin }
|
||||
|
||||
func syscallStdoutFd() int { return syscall.Stdout }
|
||||
|
||||
5
vendor/github.com/gookit/goutil/x/termenv/detect_windows.go
generated
vendored
5
vendor/github.com/gookit/goutil/x/termenv/detect_windows.go
generated
vendored
@@ -169,3 +169,8 @@ func EnableVTProcessing(stream syscall.Handle, enable bool) error {
|
||||
func syscallStdinFd() int {
|
||||
return int(syscall.Stdin)
|
||||
}
|
||||
|
||||
// on Windows, must convert to int
|
||||
func syscallStdoutFd() int {
|
||||
return int(syscall.Stdout)
|
||||
}
|
||||
|
||||
24
vendor/github.com/gookit/goutil/x/termenv/termenv.go
generated
vendored
24
vendor/github.com/gookit/goutil/x/termenv/termenv.go
generated
vendored
@@ -5,6 +5,7 @@ package termenv
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/term"
|
||||
)
|
||||
@@ -60,20 +61,37 @@ func setLastErr(err error) {
|
||||
// )
|
||||
var terminalWidth, terminalHeight int
|
||||
|
||||
// GetTermSize for current console terminal.
|
||||
// GetTermSize for current console terminal. will first try to get from environment variables COLUMNS and LINES.
|
||||
func GetTermSize(refresh ...bool) (w int, h int) {
|
||||
if terminalWidth > 0 && len(refresh) > 0 && !refresh[0] {
|
||||
if terminalWidth > 0 && (len(refresh) == 0 || !refresh[0]) {
|
||||
return terminalWidth, terminalHeight
|
||||
}
|
||||
|
||||
// 首先尝试从环境变量获取
|
||||
if cols := os.Getenv("COLUMNS"); cols != "" {
|
||||
if width, err := strconv.Atoi(cols); err == nil && width > 0 {
|
||||
terminalWidth = width
|
||||
}
|
||||
}
|
||||
if rows := os.Getenv("LINES"); rows != "" {
|
||||
if height, err := strconv.Atoi(rows); err == nil && height > 0 {
|
||||
terminalHeight = height
|
||||
}
|
||||
}
|
||||
if terminalWidth > 0 && terminalHeight > 0 {
|
||||
return terminalWidth, terminalHeight
|
||||
}
|
||||
|
||||
var err error
|
||||
w, h, err = term.GetSize(syscallStdinFd())
|
||||
w, h, err = term.GetSize(syscallStdoutFd())
|
||||
if err != nil {
|
||||
debugf("get terminal size error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// cache result
|
||||
terminalWidth, terminalHeight = w, h
|
||||
debugf("get terminal size: %d,%d", w, h)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -744,7 +744,7 @@ github.com/google/uuid
|
||||
## explicit; go 1.19
|
||||
github.com/gookit/config/v2
|
||||
github.com/gookit/config/v2/yaml
|
||||
# github.com/gookit/goutil v0.7.1
|
||||
# github.com/gookit/goutil v0.7.4
|
||||
## explicit; go 1.19
|
||||
github.com/gookit/goutil
|
||||
github.com/gookit/goutil/arrutil
|
||||
|
||||
Reference in New Issue
Block a user