Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
# GoInfo
`goutil/x/goinfo` provide some useful info for golang.
> Github: https://github.com/gookit/goutil
## Install
```bash
go get github.com/gookit/goutil/x/goinfo
```
## Go docs
- [Go docs](https://pkg.go.dev/github.com/gookit/goutil)
## Usage
```go
gover := goinfo.GoVersion() // eg: "1.15.6"
```
## Testings
```shell
go test -v ./goinfo/...
```
Test limit by regexp:
```shell
go test -v -run ^TestSetByKeys ./goinfo/...
```
+113
View File
@@ -0,0 +1,113 @@
package goinfo
import (
"reflect"
"runtime"
"strings"
"unicode"
"github.com/gookit/goutil/strutil"
)
// FullFcName struct.
type FullFcName struct {
// FullName eg: "github.com/gookit/goutil/x/goinfo.PanicIf"
FullName string
pkgPath string // "github.com/gookit/goutil/x/goinfo"
pkgName string // "goinfo"
funcName string // "PanicIf"
}
// Parse the full func name.
func (ffn *FullFcName) Parse() {
if ffn.funcName != "" {
return
}
i := strings.LastIndex(ffn.FullName, "/")
ffn.pkgPath = ffn.FullName[:i+1]
// spilt get pkg and func name
ffn.pkgName, ffn.funcName = strutil.MustCut(ffn.FullName[i+1:], ".")
ffn.pkgPath += ffn.pkgName
}
// PkgPath string get. eg: github.com/gookit/goutil/x/goinfo
func (ffn *FullFcName) PkgPath() string {
ffn.Parse()
return ffn.pkgPath
}
// PkgName string get. eg: goinfo
func (ffn *FullFcName) PkgName() string {
ffn.Parse()
return ffn.pkgName
}
// FuncName get short func name. eg: PanicIf
func (ffn *FullFcName) FuncName() string {
ffn.Parse()
return ffn.funcName
}
// String get full func name string, pkg path and func name.
func (ffn *FullFcName) String() string {
return ffn.FullName
}
// FuncName get full func name, contains pkg path.
//
// eg:
//
// // OUTPUT: github.com/gookit/goutil/x/goinfo.PkgName
// goinfo.FuncName(goinfo.PkgName)
func FuncName(fn any) string {
return runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
}
// CutFuncName get pkg path and short func name
// eg:
//
// "github.com/gookit/goutil/x/goinfo.FuncName" => [github.com/gookit/goutil/x/goinfo, FuncName]
func CutFuncName(fullFcName string) (pkgPath, shortFnName string) {
ffn := FullFcName{FullName: fullFcName}
return ffn.PkgPath(), ffn.FuncName()
}
// PkgName get current package name
//
// Usage:
//
// fullFcName := goinfo.FuncName(fn)
// pgkName := goinfo.PkgName(fullFcName)
func PkgName(fullFcName string) string {
for {
lastPeriod := strings.LastIndex(fullFcName, ".")
lastSlash := strings.LastIndex(fullFcName, "/")
if lastPeriod > lastSlash {
fullFcName = fullFcName[:lastPeriod]
} else {
break
}
}
return fullFcName
}
// GoodFuncName reports whether the function name is a valid identifier.
func GoodFuncName(name string) bool {
if name == "" {
return false
}
for i, r := range name {
switch {
case r == '_':
case i == 0 && !unicode.IsLetter(r):
return false
case !unicode.IsLetter(r) && !unicode.IsDigit(r):
return false
}
}
return true
}
+78
View File
@@ -0,0 +1,78 @@
// Package goinfo provide some standard util functions for go.
package goinfo
import (
"errors"
"os/exec"
"regexp"
"runtime"
"strings"
)
// GoVersion get go runtime version. eg: "1.18.2"
func GoVersion() string {
return runtime.Version()[2:]
}
// GoInfo define
//
// On os by:
//
// go env GOVERSION GOOS GOARCH
// go version // "go version go1.19 darwin/amd64"
type GoInfo struct {
Version string
GoOS string
Arch string
}
// match "go version go1.19 darwin/amd64"
var goVerRegex = regexp.MustCompile(`\sgo([\d.]+)\s(\w+)/(\w+)`)
// ParseGoVersion get info by parse `go version` results.
//
// Examples:
//
// line, err := sysutil.ExecLine("go version")
// if err != nil {
// return err
// }
//
// info, err := goinfo.ParseGoVersion()
// dump.P(info)
func ParseGoVersion(line string) (*GoInfo, error) {
// eg: [" go1.19 darwin/amd64", "1.19", "darwin", "amd64"]
lines := goVerRegex.FindStringSubmatch(line)
if len(lines) != 4 {
return nil, errors.New("input go version info is invalid")
}
info := &GoInfo{
Version: strings.TrimPrefix(lines[1], "go"),
}
info.GoOS = lines[2]
info.Arch = lines[3]
return info, nil
}
// OsGoInfo fetch and parse
func OsGoInfo() (*GoInfo, error) {
cmdArgs := []string{"env", "GOVERSION", "GOOS", "GOARCH"}
bs, err := exec.Command("go", cmdArgs...).Output()
if err != nil {
return nil, err
}
lines := strings.Split(strings.TrimSpace(string(bs)), "\n")
if len(lines) != len(cmdArgs)-1 {
return nil, errors.New("returns go info is not full")
}
info := &GoInfo{}
info.Version = strings.TrimPrefix(lines[0], "go")
info.GoOS = lines[1]
info.Arch = lines[2]
return info, nil
}
+166
View File
@@ -0,0 +1,166 @@
package goinfo
import (
"path/filepath"
"runtime"
"strconv"
"strings"
"github.com/gookit/goutil/x/basefn"
)
// some commonly consts
var (
DefStackLen = 10000
MaxStackLen = 100000
)
// GetCallStacks stacks is a wrapper for runtime.
// If all is true, Stack that attempts to recover the data for all goroutines.
//
// from glog package
func GetCallStacks(all bool) []byte {
// We don't know how big the traces are, so grow a few times if they don't fit.
// Start large, though.
n := DefStackLen
if all {
n = MaxStackLen
}
// 4<<10 // 4 KB should be enough
var trace []byte
for i := 0; i < 10; i++ {
trace = make([]byte, n)
bts := runtime.Stack(trace, all)
if bts < len(trace) {
return trace[:bts]
}
n *= 2
}
return trace
}
// GetCallerInfo get caller func name and with base filename and line.
//
// returns:
//
// github.com/gookit/goutil/x/goinfo_test.someFunc2(),stack_test.go:26
func GetCallerInfo(skip int) string {
skip++ // ignore current func
cs := GetCallersInfo(skip, skip+1)
return basefn.FirstOr(cs, "")
}
// SimpleCallersInfo returns an array of strings containing
// the func name, file and line number of each stack frame leading.
func SimpleCallersInfo(skip, num int) []string {
skip++ // ignore current func
return GetCallersInfo(skip, skip+num)
}
// GetCallersInfo returns an array of strings containing
// the func name, file and line number of each stack frame leading.
//
// NOTICE: max should > skip
func GetCallersInfo(skip, max int) []string {
var (
pc uintptr
ok bool
line int
file, name string
)
callers := make([]string, 0, max-skip)
for i := skip; i < max; i++ {
pc, file, line, ok = runtime.Caller(i)
if !ok {
// The breaks below failed to terminate the loop, and we ran off the
// end of the call stack.
break
}
// This is a huge edge case, but it will panic if this is the case
if file == "<autogenerated>" {
break
}
fc := runtime.FuncForPC(pc)
if fc == nil {
break
}
if strings.ContainsRune(file, '/') {
name = fc.Name()
file = filepath.Base(file)
// eg: github.com/gookit/goutil/x/goinfo_test.someFunc2(),stack_test.go:26
callers = append(callers, name+"(),"+file+":"+strconv.Itoa(line))
}
// Drop the package
// segments := strings.Split(name, ".")
// name = segments[len(segments)-1]
}
return callers
}
// CallerInfo struct
type CallerInfo struct {
PC uintptr
Fc *runtime.Func
File string
Line int
}
// String convert
func (ci *CallerInfo) String() string {
return ci.File + ":" + strconv.Itoa(ci.Line)
}
// CallerFilterFunc type
type CallerFilterFunc func(file string, fc *runtime.Func) bool
// CallersInfos returns an array of the CallerInfo, can with filters
//
// Usage:
//
// 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)
for i := skip; i < skip+num; i++ {
pc, file, line, ok := runtime.Caller(i)
if !ok {
// The breaks below failed to terminate the loop, and we ran off the
// end of the call stack.
break
}
fc := runtime.FuncForPC(pc)
if fc == nil {
continue
}
if filterLn > 0 && filters[0] != nil {
// filter - return false for skip
if !filters[0](file, fc) {
continue
}
}
// collecting
callers = append(callers, &CallerInfo{
PC: pc,
Fc: fc,
File: file,
Line: line,
})
}
return callers
}