diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71f6a2d --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Dependency directories +vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env + +build/ +.task/ diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..8b080ac --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,48 @@ +version: "2" + +linters: + enable: + - errcheck + - govet + - ineffassign + - staticcheck + - unused + - copyloopvar + - dupl + - err113 + - errname + - exptostd + - fatcontext + - funlen + - gocognit + - goconst + - gocritic + - gocyclo + - godot + - godox + - gosec + - perfsprint + - testifylint + exclusions: + rules: + - path: '(.+)_test\.go' + linters: + - errcheck + - err113 + - gosec + - gocognit + - gocyclo + settings: + testifylint: + enable-all: true + disable: + - require-error + gocognit: + min-complexity: 10 + gocyclo: + min-complexity: 10 + gocritic: + enable-all: true + settings: + hugeParam: + sizeThreshold: 255 diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..c7c7ab2 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,39 @@ +# https://taskfile.dev + +version: '3' + +vars: + GOBIN_ENV: + sh: go env GOBIN + GOPATH_ENV: + sh: go env GOPATH + BIN: '{{if .GOBIN_ENV}}{{.GOBIN_ENV}}{{else}}{{.GOPATH_ENV}}/bin{{end}}' + +tasks: + default: + desc: fmt, lint, test + deps: + - fmt + - lint + - test + + fmt: + desc: Format go files + sources: + - "*.go" + cmds: + - go fmt ./... + + lint: + desc: Statically analyze code + sources: + - '*.go' + cmds: + - golangci-lint run + + test: + desc: Run all tests + sources: + - '*.go' + cmds: + - go test -cover -race . diff --git a/errgroup.go b/errgroup.go index 1d8cffa..33e6269 100644 --- a/errgroup.go +++ b/errgroup.go @@ -131,6 +131,12 @@ func (g *Group) TryGo(f func() error) bool { return true } +type ErrgroupLimitError struct{ Size int } + +func (egerr *ErrgroupLimitError) Error() string { + return fmt.Sprintf("errgroup: modify limit while %v goroutines in the group are still active", egerr.Size) +} + // SetLimit limits the number of active goroutines in this group to at most n. // A negative value indicates no limit. // A limit of zero will prevent any new goroutines from being added. @@ -145,7 +151,8 @@ func (g *Group) SetLimit(n int) { return } if len(g.sem) != 0 { - panic(fmt.Errorf("errgroup: modify limit while %v goroutines in the group are still active", len(g.sem))) + var err error = &ErrgroupLimitError{len(g.sem)} + panic(err) } g.sem = make(chan token, n) } diff --git a/errgroup_test.go b/errgroup_test.go index 05e81e6..58b4d75 100644 --- a/errgroup_test.go +++ b/errgroup_test.go @@ -43,8 +43,6 @@ func ExampleGroup_justErrors() { "http://www.somestupidname.com/", } for _, url := range urls { - // Launch a goroutine to fetch the URL. - url := url // https://golang.org/doc/faq#closures_and_goroutines g.Go(func() error { // Fetch the URL. resp, err := http.Get(url) @@ -71,7 +69,6 @@ func ExampleGroup_parallel() { searches := []Search{Web, Image, Video} results := make([]Result, len(searches)) for i, search := range searches { - i, search := i, search // https://golang.org/doc/faq#closures_and_goroutines g.Go(func() error { result, err := search(ctx, query) if err == nil { @@ -120,7 +117,6 @@ func TestZeroGroup(t *testing.T) { var firstErr error for i, err := range tc.errs { - err := err g.Go(func() error { return err }) if firstErr == nil && err != nil { @@ -153,7 +149,6 @@ func TestWithContext(t *testing.T) { g, ctx := errgroup.WithContext(context.Background()) for _, err := range tc.errs { - err := err g.Go(func() error { return err }) } @@ -267,7 +262,6 @@ func TestCancelCause(t *testing.T) { g, ctx := errgroup.WithContext(context.Background()) for _, err := range tc.errs { - err := err g.TryGo(func() error { return err }) }