fix: disable specific staticcheck rules and update lint config (#4396)

fix: disable specific staticcheck rules and update lint config

- Disabled staticcheck rules SA1029, SA1019, S1000, and related checks
in `.golangci.yml` to filter out unwanted linter errors.
- Updated staticcheck checks list for more precise linting control.
- Clarified configuration for easier maintenance and future updates.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: hailaz <739476267@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
houseme
2025-08-29 10:32:30 +08:00
committed by GitHub
parent 71743e6903
commit 94cc233325
47 changed files with 231 additions and 208 deletions

View File

@ -4,7 +4,7 @@
# If a copy of the MIT was not distributed with this file,
# You can obtain one at https://github.com/gogf/gf.
name: GolangCI Lint
name: golangci-lint
on:
push:
branches:

View File

@ -1,7 +1,7 @@
version: "2"
run:
concurrency: 4
go: "1.23"
go: "1.25"
modules-download-mode: readonly
issues-exit-code: 2
tests: false
@ -188,7 +188,7 @@ formatters:
- blank
- default
- dot
- prefix(github.com/gogf/gf)
- prefix(github.com/gogf/gf/v2)
- prefix(github.com/gogf/gf/cmd)
- prefix(github.com/gogf/gfcontrib)
- prefix(github.com/gogf/gf/example)

View File

@ -378,7 +378,7 @@ func Test_Gen_Dao_Issue3459(t *testing.T) {
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i, _ := range files {
for i := range files {
//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
@ -450,7 +450,7 @@ func Test_Gen_Dao_Issue3749(t *testing.T) {
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i, _ := range files {
for i := range files {
//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}

View File

@ -107,7 +107,7 @@ func Test_Gen_Dao_Default(t *testing.T) {
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i, _ := range files {
for i := range files {
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
@ -208,7 +208,7 @@ func Test_Gen_Dao_TypeMapping(t *testing.T) {
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i, _ := range files {
for i := range files {
//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
@ -311,7 +311,7 @@ func Test_Gen_Dao_FieldMapping(t *testing.T) {
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i, _ := range files {
for i := range files {
//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
@ -403,7 +403,7 @@ func Test_Gen_Dao_Sqlite3(t *testing.T) {
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i, _ := range files {
for i := range files {
//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}

View File

@ -9,13 +9,14 @@ package genctrl
import (
"context"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gtag"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
const (

View File

@ -13,8 +13,6 @@ import (
"sync"
"sync/atomic"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/container/gset"
@ -25,6 +23,9 @@ import (
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gtag"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
)
const (

View File

@ -12,12 +12,13 @@ import (
"golang.org/x/tools/imports"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
// GoFmt formats the source file and adds or removes import statements as necessary.

View File

@ -498,13 +498,9 @@ func (a *SortedArray) Unique() *SortedArray {
if len(a.array) == 0 {
return a
}
i := 0
for {
if i == len(a.array)-1 {
break
}
for i := 0; i < len(a.array)-1; {
if a.getComparator()(a.array[i], a.array[i+1]) == 0 {
a.array = append(a.array[:i+1], a.array[i+1+1:]...)
a.array = append(a.array[:i+1], a.array[i+2:]...)
} else {
i++
}

View File

@ -496,13 +496,9 @@ func (a *SortedIntArray) Unique() *SortedIntArray {
if len(a.array) == 0 {
return a
}
i := 0
for {
if i == len(a.array)-1 {
break
}
for i := 0; i < len(a.array)-1; {
if a.getComparator()(a.array[i], a.array[i+1]) == 0 {
a.array = append(a.array[:i+1], a.array[i+1+1:]...)
a.array = append(a.array[:i+1], a.array[i+2:]...)
} else {
i++
}

View File

@ -498,13 +498,9 @@ func (a *SortedStrArray) Unique() *SortedStrArray {
if len(a.array) == 0 {
return a
}
i := 0
for {
if i == len(a.array)-1 {
break
}
for i := 0; i < len(a.array)-1; {
if a.getComparator()(a.array[i], a.array[i+1]) == 0 {
a.array = append(a.array[:i+1], a.array[i+1+1:]...)
a.array = append(a.array[:i+1], a.array[i+2:]...)
} else {
i++
}

View File

@ -545,7 +545,7 @@ func (m ListMap) MarshalJSON() (jsonBytes []byte, err error) {
if buffer.Len() > 1 {
buffer.WriteByte(',')
}
buffer.WriteString(fmt.Sprintf(`"%v":%s`, key, valueBytes))
fmt.Fprintf(buffer, `"%v":%s`, key, valueBytes)
return true
})
buffer.WriteByte('}')

View File

@ -166,10 +166,7 @@ func (p *Pool) checkExpireItems(ctx context.Context) {
// by comparing with this timestamp. It is not accurate comparison for
// every item expired, but high performance.
var timestampMilli = gtime.TimestampMilli()
for {
if latestExpire > timestampMilli {
break
}
for latestExpire <= timestampMilli {
if r := p.list.PopFront(); r != nil {
item := r.(*poolItem)
latestExpire = item.expireAt

View File

@ -1508,7 +1508,7 @@ func Test_Issue3968(t *testing.T) {
return nil, err
}
if result != nil {
for i, _ := range result {
for i := range result {
result[i]["location"] = gvar.New("ny")
}
}

View File

@ -598,11 +598,7 @@ func formatWhereHolder(ctx context.Context, db DB, in formatWhereHolderInput) (n
// Regular string and parameter place holder handling.
// Eg:
// Where("id in(?) and name=?", g.Slice{1,2,3}, "john")
i := 0
for {
if i >= len(in.Args) {
break
}
for i := 0; i < len(in.Args); i++ {
// ===============================================================
// Sub query, which is always used along with a string condition.
// ===============================================================
@ -621,7 +617,6 @@ func formatWhereHolder(ctx context.Context, db DB, in formatWhereHolderInput) (n
in.Args = gutil.SliceDelete(in.Args, i)
continue
}
i++
}
buffer.WriteString(whereStr)
}
@ -858,18 +853,18 @@ func handleSliceAndStructArgsForSql(
// Special struct handling.
case reflect.Struct:
switch oldArg.(type) {
switch v := oldArg.(type) {
// The underlying driver supports time.Time/*time.Time types.
case time.Time, *time.Time:
newArgs = append(newArgs, oldArg)
continue
case gtime.Time:
newArgs = append(newArgs, oldArg.(gtime.Time).Time)
newArgs = append(newArgs, v.Time)
continue
case *gtime.Time:
newArgs = append(newArgs, oldArg.(*gtime.Time).Time)
newArgs = append(newArgs, v.Time)
continue
default:

View File

@ -185,7 +185,7 @@ func checkGetSliceElementInfoForScanList(structSlicePointer any, bindToAttrName
}
if reflectKind == reflect.Slice || reflectKind == reflect.Array {
reflectType = reflectType.Elem()
reflectKind = reflectType.Kind()
// reflectKind = reflectType.Kind()
}
out.BindToAttrType = reflectType
return
@ -342,7 +342,7 @@ func doScanList(in doScanListInput) (err error) {
arrayElemValue = reflect.New(arrayItemType.Elem()).Elem()
arrayValue.Index(i).Set(arrayElemValue.Addr())
}
} else {
// } else {
// Like: []Entity
}
bindToAttrValue = arrayElemValue.FieldByName(in.BindToAttrName)

View File

@ -52,14 +52,14 @@ const errorNilAdapter = `redis adapter is not set, missing configuration or adap
// initGroup initializes the group object of redis.
func (r *Redis) initGroup() *Redis {
r.localGroup = localGroup{
localGroupGeneric: r.localAdapter.GroupGeneric(),
localGroupHash: r.localAdapter.GroupHash(),
localGroupList: r.localAdapter.GroupList(),
localGroupPubSub: r.localAdapter.GroupPubSub(),
localGroupScript: r.localAdapter.GroupScript(),
localGroupSet: r.localAdapter.GroupSet(),
localGroupSortedSet: r.localAdapter.GroupSortedSet(),
localGroupString: r.localAdapter.GroupString(),
localGroupGeneric: r.GroupGeneric(),
localGroupHash: r.GroupHash(),
localGroupList: r.GroupList(),
localGroupPubSub: r.GroupPubSub(),
localGroupScript: r.GroupScript(),
localGroupSet: r.GroupSet(),
localGroupSortedSet: r.GroupSortedSet(),
localGroupString: r.GroupString(),
}
return r
}

View File

@ -67,7 +67,7 @@ func StackWithFilters(filters []string, skip ...int) string {
if index > 9 {
space = " "
}
buffer.WriteString(fmt.Sprintf("%d.%s%s\n %s:%d\n", index, space, name, file, line))
fmt.Fprintf(buffer, "%d.%s%s\n %s:%d\n", index, space, name, file, line)
index++
} else {
break

View File

@ -17,7 +17,7 @@ import (
// Zlib compresses `data` with zlib algorithm.
func Zlib(data []byte) ([]byte, error) {
if data == nil || len(data) < 13 {
if len(data) < 13 {
return data, nil
}
var (
@ -39,7 +39,7 @@ func Zlib(data []byte) ([]byte, error) {
// UnZlib decompresses `data` with zlib algorithm.
func UnZlib(data []byte) ([]byte, error) {
if data == nil || len(data) < 13 {
if len(data) < 13 {
return data, nil
}
var (

View File

@ -89,12 +89,12 @@ func Encode(data map[string]any) (res []byte, err error) {
for section, item := range data {
// Section key-value pairs.
if m, ok = item.(map[string]any); ok {
n, err = w.WriteString(fmt.Sprintf("[%s]\n", section))
n, err = fmt.Fprintf(w, "[%s]\n", section)
if err != nil || n == 0 {
return nil, gerror.Wrapf(err, "w.WriteString failed")
}
for k, v := range m {
if n, err = w.WriteString(fmt.Sprintf("%s=%v\n", k, v)); err != nil || n == 0 {
if n, err = fmt.Fprintf(w, "%s=%v\n", k, v); err != nil || n == 0 {
return nil, gerror.Wrapf(err, "w.WriteString failed")
}
}
@ -102,7 +102,7 @@ func Encode(data map[string]any) (res []byte, err error) {
}
// Simple key-value pairs.
for k, v := range data {
if n, err = w.WriteString(fmt.Sprintf("%s=%v\n", k, v)); err != nil || n == 0 {
if n, err = fmt.Fprintf(w, "%s=%v\n", k, v); err != nil || n == 0 {
return nil, gerror.Wrapf(err, "w.WriteString failed")
}
}

View File

@ -103,7 +103,7 @@ func filterLinesOfStackInfos(infos []*stackInfo) {
func formatStackInfos(infos []*stackInfo) string {
buffer := bytes.NewBuffer(nil)
for i, info := range infos {
buffer.WriteString(fmt.Sprintf("%d. %s\n", i+1, info.Message))
fmt.Fprintf(buffer, "%d. %s\n", i+1, info.Message)
if info.Lines != nil && info.Lines.Len() > 0 {
formatStackLines(buffer, info.Lines)
}
@ -124,10 +124,11 @@ func formatStackLines(buffer *bytes.Buffer, lines *list.List) string {
if i >= 9 {
space = " "
}
buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(
buffer,
" %d).%s%s\n %s\n",
i+1, space, line.Function, line.FileLine,
))
)
}
return buffer.String()
}

View File

@ -37,7 +37,7 @@ func MiddlewareHandlerResponse(r *Request) {
r.Middleware.Next()
// There's custom buffer content, it then exits current handler.
if r.Response.BufferLength() > 0 || r.Response.Writer.BytesWritten() > 0 {
if r.Response.BufferLength() > 0 || r.Response.BytesWritten() > 0 {
return
}

View File

@ -63,7 +63,7 @@ func (s *Server) getHandlersWithCache(r *Request) (parsedItems []*HandlerItemPar
// Special http method OPTIONS handling.
// It searches the handler with the request method instead of OPTIONS method.
if method == http.MethodOptions {
if v := r.Request.Header.Get("Access-Control-Request-Method"); v != "" {
if v := r.Header.Get("Access-Control-Request-Method"); v != "" {
method = v
}
}

View File

@ -326,7 +326,7 @@ func Test_Router_Handler_Standard_WithGeneric(t *testing.T) {
})
s.BindHandler("/test1_slice", func(ctx context.Context, req *TestReq) (res []Test1Res, err error) {
return []Test1Res{
Test1Res{
{
Age: TestGeneric[int]{
Test: req.Age,
},
@ -341,7 +341,7 @@ func Test_Router_Handler_Standard_WithGeneric(t *testing.T) {
s.BindHandler("/test2_slice", func(ctx context.Context, req *TestReq) (res []Test2Res, err error) {
return []Test2Res{
Test2Res{
{
Test: req.Age,
},
}, nil
@ -359,7 +359,7 @@ func Test_Router_Handler_Standard_WithGeneric(t *testing.T) {
s.BindHandler("/test3_slice", func(ctx context.Context, req *TestReq) (res []TestGenericRes[int], err error) {
return []TestGenericRes[int]{
TestGenericRes[int]{
{
Test: req.Age,
},
}, nil

View File

@ -24,7 +24,7 @@ func GetIpArray() (ips []string, err error) {
}
for _, address := range interfaceAddr {
ipNet, isValidIpNet := address.(*net.IPNet)
if !(isValidIpNet && !ipNet.IP.IsLoopback()) {
if !isValidIpNet || ipNet.IP.IsLoopback() {
continue
}
if ipNet.IP.To4() != nil {

View File

@ -85,7 +85,7 @@ func (oai *OpenApiV3) addPath(in addPathInput) error {
}
var (
mime string
// mime string
path = Path{XExtensions: make(XExtensions)}
inputMetaMap = gmeta.Data(inputObject.Interface())
outputMetaMap = gmeta.Data(outputObject.Interface())
@ -152,9 +152,9 @@ func (oai *OpenApiV3) addPath(in addPathInput) error {
return err
}
// Allowed request mime.
if mime = inputMetaMap[gtag.Mime]; mime == "" {
mime = inputMetaMap[gtag.Consumes]
}
// if mime = inputMetaMap[gtag.Mime]; mime == "" {
// mime = inputMetaMap[gtag.Consumes]
// }
}
// path security

View File

@ -472,7 +472,6 @@ func (c *AdapterMemory) handleLruKey(ctx context.Context, keys ...any) {
_, _ = c.doRemove(ctx, evictedKeys...)
return
}
return
}
// clearByKey deletes the key-value pair with given `key`.

View File

@ -56,20 +56,20 @@ func (a *AdapterFile) SetPath(directoryPath string) (err error) {
if realPath == "" {
buffer := bytes.NewBuffer(nil)
if a.searchPaths.Len() > 0 {
buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(buffer,
`SetPath failed: cannot find directory "%s" in following paths:`,
directoryPath,
))
)
a.searchPaths.RLockFunc(func(array []string) {
for k, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
fmt.Fprintf(buffer, "\n%d. %s", k+1, v)
}
})
} else {
buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(buffer,
`SetPath failed: path "%s" does not exist`,
directoryPath,
))
)
}
return gerror.New(buffer.String())
}
@ -136,20 +136,18 @@ func (a *AdapterFile) doAddPath(directoryPath string) (err error) {
if realPath == "" {
buffer := bytes.NewBuffer(nil)
if a.searchPaths.Len() > 0 {
buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(buffer,
`AddPath failed: cannot find directory "%s" in following paths:`,
directoryPath,
))
directoryPath)
a.searchPaths.RLockFunc(func(array []string) {
for k, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
fmt.Fprintf(buffer, "\n%d. %s", k+1, v)
}
})
} else {
buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(buffer,
`AddPath failed: path "%s" does not exist`,
directoryPath,
))
directoryPath)
}
return gerror.New(buffer.String())
}
@ -269,34 +267,30 @@ func (a *AdapterFile) GetFilePath(fileNameOrPath ...string) (filePath string, er
var buffer = bytes.NewBuffer(nil)
if a.searchPaths.Len() > 0 {
if !gstr.InArray(supportedFileTypes, fileExtName) {
buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(buffer,
`possible config files "%s" or "%s" not found in resource manager or following system searching paths:`,
usedFileNameOrPath, fmt.Sprintf(`%s.%s`, usedFileNameOrPath, gstr.Join(supportedFileTypes, "/")),
))
usedFileNameOrPath, fmt.Sprintf(`%s.%s`, usedFileNameOrPath, gstr.Join(supportedFileTypes, "/")))
} else {
buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(buffer,
`specified config file "%s" not found in resource manager or following system searching paths:`,
usedFileNameOrPath,
))
usedFileNameOrPath)
}
a.searchPaths.RLockFunc(func(array []string) {
index := 1
for _, searchPath := range array {
searchPath = gstr.TrimRight(searchPath, `\/`)
for _, tryFolder := range localSystemTryFolders {
buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(buffer,
"\n%d. %s",
index, gfile.Join(searchPath, tryFolder),
))
index, gfile.Join(searchPath, tryFolder))
index++
}
}
})
} else {
buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(buffer,
`cannot find config file "%s" with no filePath configured`,
usedFileNameOrPath,
))
usedFileNameOrPath)
}
err = gerror.NewCode(gcode.CodeNotFound, buffer.String())
}

View File

@ -46,14 +46,14 @@ func (c *Command) RunWithValue(ctx context.Context) (value any) {
buffer = bytes.NewBuffer(nil)
)
if code.Code() == gcode.CodeNotFound.Code() {
buffer.WriteString(fmt.Sprintf("ERROR: %s\n", gstr.Trim(err.Error())))
fmt.Fprintf(buffer, "ERROR: %s\n", gstr.Trim(err.Error()))
if lastCmd, ok := detail.(*Command); ok {
lastCmd.PrintTo(buffer)
} else {
c.PrintTo(buffer)
}
} else {
buffer.WriteString(fmt.Sprintf("%+v\n", err))
fmt.Fprintf(buffer, "%+v\n", err)
}
if gtrace.GetTraceID(ctx) == "" {
fmt.Println(buffer.String())

View File

@ -19,30 +19,26 @@ func (s *cronSchedule) getAndUpdateLastCheckTimestamp(ctx context.Context, t tim
currentTimestamp = t.Unix()
lastCheckTimestamp = s.lastCheckTimestamp.Val()
)
switch {
switch lastCheckTimestamp {
// Often happens, timer triggers in the same second, but the millisecond is different.
// Example:
// lastCheckTimestamp: 2024-03-26 19:47:34.000
// currentTimestamp: 2024-03-26 19:47:34.999
case
lastCheckTimestamp == currentTimestamp:
case currentTimestamp:
lastCheckTimestamp += 1
// Often happens, no latency.
// Example:
// lastCheckTimestamp: 2024-03-26 19:47:34.000
// currentTimestamp: 2024-03-26 19:47:35.000
case
lastCheckTimestamp == currentTimestamp-1:
case currentTimestamp - 1:
lastCheckTimestamp = currentTimestamp
// Latency in 3 seconds, which can be tolerant.
// Example:
// lastCheckTimestamp: 2024-03-26 19:47:31.000、2024-03-26 19:47:32.000
// currentTimestamp: 2024-03-26 19:47:34.000
case
lastCheckTimestamp == currentTimestamp-2,
lastCheckTimestamp == currentTimestamp-3:
case currentTimestamp - 2, currentTimestamp - 3:
lastCheckTimestamp += 1
// Too much latency, it ignores the fix, the cron job might not be triggered.

View File

@ -46,10 +46,10 @@ func Search(name string, prioritySearchPaths ...string) (realPath string, err er
// If it fails searching, it returns formatted error.
if realPath == "" {
buffer := bytes.NewBuffer(nil)
buffer.WriteString(fmt.Sprintf(`cannot find "%s" in following paths:`, name))
fmt.Fprintf(buffer, `cannot find "%s" in following paths:`, name)
array.RLockFunc(func(array []string) {
for k, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
fmt.Fprintf(buffer, "\n%d. %s", k+1, v)
}
})
err = gerror.New(buffer.String())

View File

@ -63,7 +63,7 @@ func doZipPathWriter(srcPath string, zipWriter *zip.Writer, option ...Option) er
files = []string{absolutePath}
}
headerPrefix := usedOption.Prefix
if !(headerPrefix == "/") {
if headerPrefix != "/" {
headerPrefix = strings.TrimRight(headerPrefix, `\/`)
}
if headerPrefix != "" && gfile.IsDir(absolutePath) {
@ -124,8 +124,7 @@ func zipFile(path string, prefix string, zw *zip.Writer) error {
prefix = strings.ReplaceAll(prefix, `//`, `/`)
file, err := os.Open(path)
if err != nil {
err = gerror.Wrapf(err, `os.Open failed for path "%s"`, path)
return nil
return gerror.Wrapf(err, `os.Open failed for path "%s"`, path)
}
defer file.Close()

View File

@ -52,9 +52,7 @@ func New(path string, cache bool) *SPath {
sp.cache = gmap.NewStrStrMap(true)
}
if len(path) > 0 {
if _, err := sp.Add(path); err != nil {
// intlog.Print(err)
}
_, _ = sp.Add(path)
}
return sp
}

View File

@ -31,7 +31,7 @@ const (
H = time.Hour
M = time.Minute
S = time.Second
MS = time.Millisecond
MS = time.Millisecond //nolint:staticcheck
US = time.Microsecond
NS = time.Nanosecond

View File

@ -460,7 +460,7 @@ func (t *Time) StartOfHalf() *Time {
func (t *Time) StartOfYear() *Time {
y, _, _ := t.Date()
newTime := t.Clone()
newTime.Time = time.Date(y, time.January, 1, 0, 0, 0, 0, newTime.Time.Location())
newTime.Time = time.Date(y, time.January, 1, 0, 0, 0, 0, newTime.Location())
return newTime
}
@ -487,7 +487,7 @@ func (t *Time) EndOfDay(withNanoPrecision ...bool) *Time {
y, m, d := t.Date()
newTime := t.Clone()
newTime.Time = time.Date(
y, m, d, 23, 59, 59, int(time.Second-getPrecisionDelta(withNanoPrecision...)), newTime.Time.Location(),
y, m, d, 23, 59, 59, int(time.Second-getPrecisionDelta(withNanoPrecision...)), newTime.Location(),
)
return newTime
}

View File

@ -81,7 +81,7 @@ func SetTimeZone(zone string) (err error) {
// ToLocation converts current time to specified location.
func (t *Time) ToLocation(location *time.Location) *Time {
newTime := t.Clone()
newTime.Time = newTime.Time.In(location)
newTime.Time = newTime.In(location)
return newTime
}

View File

@ -86,9 +86,9 @@ func (view *View) SetConfigWithMap(m map[string]any) error {
_, v1 := gutil.MapPossibleItemByKey(m, "paths")
_, v2 := gutil.MapPossibleItemByKey(m, "path")
if v1 == nil && v2 != nil {
switch v2.(type) {
switch v2 := v2.(type) {
case string:
m["paths"] = []string{v2.(string)}
m["paths"] = []string{v2}
case []string:
m["paths"] = v2
}

View File

@ -444,22 +444,21 @@ func (view *View) searchFile(ctx context.Context, file string) (path string, fol
if path == "" {
buffer := bytes.NewBuffer(nil)
if view.searchPaths.Len() > 0 {
buffer.WriteString(fmt.Sprintf("cannot find template file \"%s\" in following paths:", file))
fmt.Fprintf(buffer, "cannot find template file \"%s\" in following paths:", file)
view.searchPaths.RLockFunc(func(array []string) {
index := 1
for _, searchPath := range array {
searchPath = gstr.TrimRight(searchPath, `\/`)
for _, tryFolder := range localSystemTryFolders {
buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(buffer,
"\n%d. %s",
index, gfile.Join(searchPath, tryFolder),
))
index, gfile.Join(searchPath, tryFolder))
index++
}
}
})
} else {
buffer.WriteString(fmt.Sprintf("cannot find template file \"%s\" with no path set/add", file))
fmt.Fprintf(buffer, "cannot find template file \"%s\" with no path set/add", file)
}
if errorPrint() {
glog.Error(ctx, buffer.String())

View File

@ -9,7 +9,6 @@ package gstr
import (
"bytes"
"fmt"
"math"
"regexp"
"strconv"
"strings"
@ -135,30 +134,57 @@ func Shuffle(str string) string {
// HideStr replaces part of the string `str` to `hide` by `percentage` from the `middle`.
// It considers parameter `str` as unicode string.
func HideStr(str string, percent int, hide string) string {
array := strings.Split(str, "@")
if len(array) > 1 {
str = array[0]
// Handle email case
var suffix string
if idx := strings.IndexByte(str, '@'); idx >= 0 {
suffix = str[idx:]
str = str[:idx]
}
var (
rs = []rune(str)
length = len(rs)
mid = math.Floor(float64(length / 2))
hideLen = int(math.Floor(float64(length) * (float64(percent) / 100)))
start = int(mid - math.Floor(float64(hideLen)/2))
hideStr = []rune("")
hideRune = []rune(hide)
)
for i := 0; i < hideLen; i++ {
hideStr = append(hideStr, hideRune...)
// Early return for edge cases
if str == "" || percent <= 0 {
return str + suffix
}
buffer := bytes.NewBuffer(nil)
buffer.WriteString(string(rs[0:start]))
buffer.WriteString(string(hideStr))
buffer.WriteString(string(rs[start+hideLen:]))
if len(array) > 1 {
buffer.WriteString("@" + array[1])
if percent >= 100 {
return strings.Repeat(hide, len([]rune(str))) + suffix
}
return buffer.String()
rs := []rune(str)
length := len(rs)
if length == 0 {
return str + suffix
}
// Calculate hideLen using the same logic as original (with floor)
hideLen := (length * percent) / 100
if hideLen == 0 {
return str + suffix
}
// Calculate start position: mid - hideLen/2
// This matches the original algorithm behavior
mid := length / 2
start := max(mid-hideLen/2, 0)
end := start + hideLen
if end > length {
end = length
start = max(length-hideLen, 0)
}
// Pre-calculate capacity to avoid reallocations
var builder strings.Builder
builder.Grow(len(str) + len(hide)*hideLen + len(suffix))
// Build result string efficiently
builder.WriteString(string(rs[:start]))
if hide != "" {
builder.WriteString(strings.Repeat(hide, hideLen))
}
builder.WriteString(string(rs[end:]))
builder.WriteString(suffix)
return builder.String()
}
// Nl2Br inserts HTML line breaks(`br`|<br />) before all newlines in a string:
@ -207,9 +233,8 @@ func WordWrap(str string, width int, br string) string {
wordBuf, spaceBuf bytes.Buffer
init = make([]byte, 0, len(str))
buf = bytes.NewBuffer(init)
strRunes = []rune(str)
)
for _, char := range strRunes {
for _, char := range str {
switch {
case char == '\n':
if wordBuf.Len() == 0 {

View File

@ -29,7 +29,7 @@ func CountI(s, substr string) int {
func CountWords(str string) map[string]int {
m := make(map[string]int)
buffer := bytes.NewBuffer(nil)
for _, r := range []rune(str) {
for _, r := range str {
if unicode.IsSpace(r) {
if buffer.Len() > 0 {
m[buffer.String()]++
@ -46,14 +46,11 @@ func CountWords(str string) map[string]int {
}
// CountChars returns information about chars' count used in a string.
// It considers parameter `str` as unicode string.
// It considers parameter `str` as Unicode string.
func CountChars(str string, noSpace ...bool) map[string]int {
m := make(map[string]int)
countSpace := true
if len(noSpace) > 0 && noSpace[0] {
countSpace = false
}
for _, r := range []rune(str) {
countSpace := len(noSpace) == 0 || !noSpace[0]
for _, r := range str {
if !countSpace && unicode.IsSpace(r) {
continue
}

View File

@ -25,7 +25,6 @@ func Levenshtein(str1, str2 string, costIns, costRep, costDel int) int {
return -1
}
tmp := make([]int, l2+1)
p1 := make([]int, l2+1)
p2 := make([]int, l2+1)
var c0, c1, c2 int
@ -51,9 +50,7 @@ func Levenshtein(str1, str2 string, costIns, costRep, costDel int) int {
}
p2[i2+1] = c0
}
tmp = p1
p1 = p2
p2 = tmp
p1, p2 = p2, p1
}
c0 = p1[l2]

View File

@ -9,6 +9,9 @@ package gstr
import (
"strings"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/gogf/gf/v2/internal/utils"
)
@ -40,7 +43,7 @@ func LcFirst(s string) string {
// UcWords uppercase the first character of each word in a string.
func UcWords(str string) string {
return strings.Title(str)
return cases.Title(language.Und).String(str)
}
// IsLetterLower tests whether the given byte b is in lower case.

View File

@ -54,7 +54,7 @@ func Test_LcFirst(t *testing.T) {
func Test_UcWords(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := "我爱GF: i love go frame"
e1 := "我爱GF: I Love Go Frame"
e1 := "我爱Gf: I Love Go Frame"
t.Assert(gstr.UcWords(s1), e1)
})
}
@ -178,9 +178,9 @@ func Test_SplitAndTrim(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := `
010
010
020
020
`
a := gstr.SplitAndTrim(s, "\n", "0")
@ -321,6 +321,35 @@ func Test_HideStr(t *testing.T) {
t.Assert(gstr.HideStr("张三", 50, "*"), "张*")
t.Assert(gstr.HideStr("张小三", 50, "*"), "张*三")
t.Assert(gstr.HideStr("欧阳小三", 50, "*"), "欧**三")
// 边界与特殊用例扩展
// 1) 空字符串与非正百分比
t.Assert(gstr.HideStr("", 50, "*"), "")
t.Assert(gstr.HideStr("abcdef", 0, "*"), "abcdef")
t.Assert(gstr.HideStr("abcdef", -1, "*"), "abcdef")
// 2) 百分比为100完全隐藏邮箱仅隐藏本地部分
t.Assert(gstr.HideStr("abcdef", 100, "*"), "******")
t.Assert(gstr.HideStr("user@example.com", 100, "*"), "****@example.com")
// 3) 极短字符串
t.Assert(gstr.HideStr("a", 100, "*"), "*")
t.Assert(gstr.HideStr("ab", 50, "*"), "a*")
// 百分比太小时四舍五入前为0应保持不变
t.Assert(gstr.HideStr("ab", 10, "*"), "ab")
// 4) 隐藏字符为空:相当于删除中间片段
t.Assert(gstr.HideStr("abcdef", 50, ""), "abf")
t.Assert(gstr.HideStr("john@kohg.cn", 50, ""), "jn@kohg.cn")
// 5) 多字符隐藏串
t.Assert(gstr.HideStr("abcde", 40, "##"), "a####de")
// 6) Unicode/emoji
t.Assert(gstr.HideStr("你好🙂世界", 40, "*"), "你**世界")
// 7) 多个@的字符串,按第一个@处理
t.Assert(gstr.HideStr("a@b@c", 100, "*"), "*@b@c")
})
}

View File

@ -271,7 +271,7 @@ func doScanList(
arrayElemValue = reflect.New(arrayItemType.Elem()).Elem()
arrayValue.Index(i).Set(arrayElemValue.Addr())
}
} else {
// } else {
// Like: []Entity
}
bindToAttrValue = arrayElemValue.FieldByName(bindToAttrName)

View File

@ -108,10 +108,11 @@ func (c *Converter) Int64(anyInput any) (int64, error) {
isMinus = false
)
if len(s) > 0 {
if s[0] == '-' {
switch s[0] {
case '-':
isMinus = true
s = s[1:]
} else if s[0] == '+' {
case '+':
s = s[1:]
}
}

View File

@ -67,6 +67,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ...ScanOption) (er
if dstPointerReflectValue.CanAddr() {
dstPointerReflectValue = dstPointerReflectValue.Addr()
dstPointerReflectType = dstPointerReflectValue.Type()
// dstPointerReflectKind = dstPointerReflectType.Kind()
} else {
// If dstPointer is not a pointer and cannot be addressed, return an error
return gerror.NewCodef(

View File

@ -111,7 +111,7 @@ func (p *Page) LastPage() string {
// PageBar returns the HTML page bar content with link and span tags.
func (p *Page) PageBar() string {
plus := int(math.Ceil(float64(p.PageBarNum / 2)))
plus := p.PageBarNum / 2
if p.PageBarNum-plus+p.CurrentPage > p.TotalPage {
plus = p.PageBarNum - p.TotalPage + p.CurrentPage
}

View File

@ -176,13 +176,13 @@ func doDump(value any, indent string, buffer *bytes.Buffer, option doDumpOption)
doDumpNumber(exportInternalInput)
case reflect.Chan:
buffer.WriteString(fmt.Sprintf(`<%s>`, reflectValue.Type().String()))
fmt.Fprintf(buffer, `<%s>`, reflectValue.Type().String())
case reflect.Func:
if reflectValue.IsNil() || !reflectValue.IsValid() {
buffer.WriteString(`<nil>`)
} else {
buffer.WriteString(fmt.Sprintf(`<%s>`, reflectValue.Type().String()))
fmt.Fprintf(buffer, `<%s>`, reflectValue.Type().String())
}
case reflect.Interface:
@ -209,14 +209,9 @@ type doDumpInternalInput struct {
func doDumpSlice(in doDumpInternalInput) {
if b, ok := in.Value.([]byte); ok {
if !in.Option.WithType {
in.Buffer.WriteString(fmt.Sprintf(`"%s"`, addSlashesForString(string(b))))
fmt.Fprintf(in.Buffer, `"%s"`, addSlashesForString(string(b)))
} else {
in.Buffer.WriteString(fmt.Sprintf(
`%s(%d) "%s"`,
in.ReflectTypeName,
len(string(b)),
string(b),
))
fmt.Fprintf(in.Buffer, `%s(%d) "%s"`, in.ReflectTypeName, len(string(b)), string(b))
}
return
}
@ -224,21 +219,21 @@ func doDumpSlice(in doDumpInternalInput) {
if !in.Option.WithType {
in.Buffer.WriteString("[]")
} else {
in.Buffer.WriteString(fmt.Sprintf("%s(0) []", in.ReflectTypeName))
fmt.Fprintf(in.Buffer, "%s(0) []", in.ReflectTypeName)
}
return
}
if !in.Option.WithType {
in.Buffer.WriteString("[\n")
} else {
in.Buffer.WriteString(fmt.Sprintf("%s(%d) [\n", in.ReflectTypeName, in.ReflectValue.Len()))
fmt.Fprintf(in.Buffer, "%s(%d) [\n", in.ReflectTypeName, in.ReflectValue.Len())
}
for i := 0; i < in.ReflectValue.Len(); i++ {
in.Buffer.WriteString(in.NewIndent)
doDump(in.ReflectValue.Index(i), in.NewIndent, in.Buffer, in.Option)
in.Buffer.WriteString(",\n")
}
in.Buffer.WriteString(fmt.Sprintf("%s]", in.Indent))
fmt.Fprintf(in.Buffer, "%s]", in.Indent)
}
func doDumpMap(in doDumpInternalInput) {
@ -254,7 +249,7 @@ func doDumpMap(in doDumpInternalInput) {
if !in.Option.WithType {
in.Buffer.WriteString("{}")
} else {
in.Buffer.WriteString(fmt.Sprintf("%s(0) {}", in.ReflectTypeName))
fmt.Fprintf(in.Buffer, "%s(0) {}", in.ReflectTypeName)
}
return
}
@ -272,7 +267,7 @@ func doDumpMap(in doDumpInternalInput) {
if !in.Option.WithType {
in.Buffer.WriteString("{\n")
} else {
in.Buffer.WriteString(fmt.Sprintf("%s(%d) {\n", in.ReflectTypeName, len(mapKeys)))
fmt.Fprintf(in.Buffer, "%s(%d) {\n", in.ReflectTypeName, len(mapKeys))
}
for _, mapKey := range mapKeys {
tmpSpaceNum = len(fmt.Sprintf(`%v`, mapKey.Interface()))
@ -283,32 +278,34 @@ func doDumpMap(in doDumpInternalInput) {
}
// Map key and indent string dump.
if !in.Option.WithType {
in.Buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(
in.Buffer,
"%s%v:%s",
in.NewIndent,
mapKeyStr,
strings.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
))
)
} else {
in.Buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(
in.Buffer,
"%s%s(%v):%s",
in.NewIndent,
mapKey.Type().String(),
mapKeyStr,
strings.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
))
)
}
// Map value dump.
doDump(in.ReflectValue.MapIndex(mapKey), in.NewIndent, in.Buffer, in.Option)
in.Buffer.WriteString(",\n")
}
in.Buffer.WriteString(fmt.Sprintf("%s}", in.Indent))
fmt.Fprintf(in.Buffer, "%s}", in.Indent)
}
func doDumpStruct(in doDumpInternalInput) {
if in.PtrAddress != "" {
if _, ok := in.DumpedPointerSet[in.PtrAddress]; ok {
in.Buffer.WriteString(fmt.Sprintf(`<cycle dump %s>`, in.PtrAddress))
fmt.Fprintf(in.Buffer, `<cycle dump %s>`, in.PtrAddress)
return
}
}
@ -355,12 +352,13 @@ func doDumpStruct(in doDumpInternalInput) {
if !in.Option.WithType {
in.Buffer.WriteString(structContentStr)
} else {
in.Buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(
in.Buffer,
"%s(%s) %s",
in.ReflectTypeName,
attributeCountStr,
structContentStr,
))
)
}
return
}
@ -382,37 +380,39 @@ dumpStructFields:
if !in.Option.WithType {
in.Buffer.WriteString("{\n")
} else {
in.Buffer.WriteString(fmt.Sprintf("%s(%d) {\n", in.ReflectTypeName, len(structFields)))
fmt.Fprintf(in.Buffer, "%s(%d) {\n", in.ReflectTypeName, len(structFields))
}
for _, field := range structFields {
if in.ExportedOnly && !field.IsExported() {
continue
}
tmpSpaceNum = len(fmt.Sprintf(`%v`, field.Name()))
in.Buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(
in.Buffer,
"%s%s:%s",
in.NewIndent,
field.Name(),
strings.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
))
)
doDump(field.Value, in.NewIndent, in.Buffer, in.Option)
in.Buffer.WriteString(",\n")
}
in.Buffer.WriteString(fmt.Sprintf("%s}", in.Indent))
fmt.Fprintf(in.Buffer, "%s}", in.Indent)
}
func doDumpNumber(in doDumpInternalInput) {
if v, ok := in.Value.(iString); ok {
s := v.String()
if !in.Option.WithType {
in.Buffer.WriteString(fmt.Sprintf(`"%v"`, addSlashesForString(s)))
fmt.Fprintf(in.Buffer, `"%v"`, addSlashesForString(s))
} else {
in.Buffer.WriteString(fmt.Sprintf(
`%s(%d) "%v"`,
fmt.Fprintf(
in.Buffer,
"%s(%d) %s",
in.ReflectTypeName,
len(s),
addSlashesForString(s),
))
fmt.Sprintf(`"%v"`, addSlashesForString(s)),
)
}
} else {
doDumpDefault(in)
@ -422,14 +422,15 @@ func doDumpNumber(in doDumpInternalInput) {
func doDumpString(in doDumpInternalInput) {
s := in.ReflectValue.String()
if !in.Option.WithType {
in.Buffer.WriteString(fmt.Sprintf(`"%v"`, addSlashesForString(s)))
fmt.Fprintf(in.Buffer, `"%v"`, addSlashesForString(s))
} else {
in.Buffer.WriteString(fmt.Sprintf(
fmt.Fprintf(
in.Buffer,
`%s(%d) "%v"`,
in.ReflectTypeName,
len(s),
addSlashesForString(s),
))
)
}
}
@ -458,7 +459,7 @@ func doDumpDefault(in doDumpInternalInput) {
if !in.Option.WithType {
in.Buffer.WriteString(s)
} else {
in.Buffer.WriteString(fmt.Sprintf("%s(%s)", in.ReflectTypeName, s))
fmt.Fprintf(in.Buffer, "%s(%s)", in.ReflectTypeName, s)
}
}