mirror of
https://github.com/gojp/goreportcard.git
synced 2026-01-28 22:39:05 +08:00
update gocyclo
This commit is contained in:
@@ -334,7 +334,12 @@ func GoTool(dir string, filenames, command []string) (float64, []FileSummary, er
|
||||
|
||||
params := command[1:]
|
||||
params = addSkipDirs(params)
|
||||
params = append(params, dir+"/...")
|
||||
|
||||
if strings.Contains(command[len(command)-1], "cyclo") {
|
||||
params = append(params, dir)
|
||||
} else {
|
||||
params = append(params, dir+"/...")
|
||||
}
|
||||
|
||||
cmd := exec.Command(command[0], params...)
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
|
||||
2
go.mod
2
go.mod
@@ -4,7 +4,6 @@ go 1.16
|
||||
|
||||
require (
|
||||
github.com/DataDog/zstd v1.4.8 // indirect
|
||||
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214
|
||||
github.com/alecthomas/gometalinter v1.0.3
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 // indirect
|
||||
@@ -14,6 +13,7 @@ require (
|
||||
github.com/dgraph-io/ristretto v0.0.3 // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/fzipp/gocyclo v0.3.1
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.3 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
|
||||
12
go.sum
12
go.sum
@@ -5,8 +5,6 @@ github.com/DataDog/zstd v1.4.8 h1:Rpmta4xZ/MgZnriKNd24iZMhGpP5dvUcs/uqfBapKZY=
|
||||
github.com/DataDog/zstd v1.4.8/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214 h1:YI/8G3uLbYyowJeOPVL6BMKe2wbL54h0FdEKmncU6lU=
|
||||
github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214/go.mod h1:Ef5UOtJdJ5rVFObdOVsrNgKV/Wf4I+daTCSk8GTrHIk=
|
||||
github.com/alecthomas/gometalinter v1.0.3 h1:Y5sxwml3eb93scdwfdOOh5VDULOtOEuCMrOnRpRwn1w=
|
||||
github.com/alecthomas/gometalinter v1.0.3/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
@@ -38,6 +36,8 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fzipp/gocyclo v0.3.1 h1:A9UeX3HJSXTBzvHzhqoYVuE0eAhe+aM8XBCCwsPMZOc=
|
||||
github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
@@ -50,8 +50,6 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20210522101830-0589229737b2 h1:hC4RAQwLzbDbHsa+CwwGBm1uG2oX9o3Frx9G73duPi8=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20210522101830-0589229737b2/go.mod h1:M9mZEtGIsR1oDaZagNPNG9iq9n2HrhZ17dsXk73V3Lw=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 h1:PVRE9d4AQKmbelZ7emNig1+NT27DUmKZn5qXxfio54U=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
@@ -106,14 +104,12 @@ golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
@@ -131,8 +127,6 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211015200801-69063c4bb744 h1:KzbpndAYEM+4oHRp9JmB2ewj0NHHxO3Z0g7Gus2O1kk=
|
||||
golang.org/x/sys v0.0.0-20211015200801-69063c4bb744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -144,8 +138,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.3 h1:L69ShwSZEyCsLKoAxDKeMvLDZkumEe8gXUZAjab0tX8=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
go install ./vendor/github.com/alecthomas/gometalinter
|
||||
|
||||
go install ./vendor/golang.org/x/lint/golint
|
||||
go install ./vendor/github.com/alecthomas/gocyclo
|
||||
go install ./vendor/github.com/fzipp/gocyclo
|
||||
go install ./vendor/github.com/gordonklaus/ineffassign
|
||||
go install ./vendor/github.com/client9/misspell
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
_ "github.com/alecthomas/gocyclo"
|
||||
_ "github.com/alecthomas/gometalinter"
|
||||
_ "github.com/client9/misspell/cmd/misspell"
|
||||
_ "github.com/fzipp/gocyclo/cmd/gocyclo"
|
||||
_ "github.com/gordonklaus/ineffassign"
|
||||
_ "golang.org/x/lint/golint"
|
||||
_ "honnef.co/go/tools/cmd/staticcheck"
|
||||
|
||||
31
vendor/github.com/alecthomas/gocyclo/README.md
generated
vendored
31
vendor/github.com/alecthomas/gocyclo/README.md
generated
vendored
@@ -1,31 +0,0 @@
|
||||
Gocyclo calculates cyclomatic complexities of functions in Go source code.
|
||||
|
||||
The cyclomatic complexity of a function is calculated according to the
|
||||
following rules:
|
||||
|
||||
1 is the base complexity of a function
|
||||
+1 for each 'if', 'for', 'case', '&&' or '||'
|
||||
|
||||
To install, run
|
||||
|
||||
$ go get github.com/fzipp/gocyclo
|
||||
|
||||
and put the resulting binary in one of your PATH directories if
|
||||
`$GOPATH/bin` isn't already in your PATH.
|
||||
|
||||
Usage:
|
||||
|
||||
$ gocyclo [<flag> ...] <Go file or directory> ...
|
||||
|
||||
Examples:
|
||||
|
||||
$ gocyclo .
|
||||
$ gocyclo main.go
|
||||
$ gocyclo -top 10 src/
|
||||
$ gocyclo -over 25 docker
|
||||
$ gocyclo -avg .
|
||||
|
||||
The output fields for each line are:
|
||||
|
||||
<complexity> <package> <function> <file:row:column>
|
||||
|
||||
222
vendor/github.com/alecthomas/gocyclo/gocyclo.go
generated
vendored
222
vendor/github.com/alecthomas/gocyclo/gocyclo.go
generated
vendored
@@ -1,222 +0,0 @@
|
||||
// Copyright 2013 Frederik Zipp. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Gocyclo calculates the cyclomatic complexities of functions and
|
||||
// methods in Go source code.
|
||||
//
|
||||
// Usage:
|
||||
// gocyclo [<flag> ...] <Go file or directory> ...
|
||||
//
|
||||
// Flags
|
||||
// -over N show functions with complexity > N only and
|
||||
// return exit code 1 if the output is non-empty
|
||||
// -top N show the top N most complex functions only
|
||||
// -avg show the average complexity
|
||||
//
|
||||
// The output fields for each line are:
|
||||
// <complexity> <package> <function> <file:row:column>
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
)
|
||||
|
||||
const usageDoc = `Calculate cyclomatic complexities of Go functions.
|
||||
usage:
|
||||
gocyclo [<flag> ...] <Go file or directory> ...
|
||||
|
||||
Flags
|
||||
-over N show functions with complexity > N only and
|
||||
return exit code 1 if the set is non-empty
|
||||
-top N show the top N most complex functions only
|
||||
-avg show the average complexity over all functions,
|
||||
not depending on whether -over or -top are set
|
||||
|
||||
The output fields for each line are:
|
||||
<complexity> <package> <function> <file:row:column>
|
||||
`
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, usageDoc)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
var (
|
||||
over = flag.Int("over", 0, "show functions with complexity > N only")
|
||||
top = flag.Int("top", -1, "show the top N most complex functions only")
|
||||
avg = flag.Bool("avg", false, "show the average complexity")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
if len(args) == 0 {
|
||||
usage()
|
||||
}
|
||||
|
||||
stats := analyze(args)
|
||||
sort.Sort(byComplexity(stats))
|
||||
written := writeStats(os.Stdout, stats)
|
||||
|
||||
if *avg {
|
||||
showAverage(stats)
|
||||
}
|
||||
|
||||
if *over > 0 && written > 0 {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func analyze(paths []string) []stat {
|
||||
stats := make([]stat, 0)
|
||||
for _, path := range paths {
|
||||
if isDir(path) {
|
||||
stats = analyzeDir(path, stats)
|
||||
} else {
|
||||
stats = analyzeFile(path, stats)
|
||||
}
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
func isDir(filename string) bool {
|
||||
fi, err := os.Stat(filename)
|
||||
return err == nil && fi.IsDir()
|
||||
}
|
||||
|
||||
func analyzeFile(fname string, stats []stat) []stat {
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, fname, nil, 0)
|
||||
if err != nil {
|
||||
exitError(err)
|
||||
}
|
||||
return buildStats(f, fset, stats)
|
||||
}
|
||||
|
||||
func analyzeDir(dirname string, stats []stat) []stat {
|
||||
files, _ := filepath.Glob(filepath.Join(dirname, "*.go"))
|
||||
for _, file := range files {
|
||||
stats = analyzeFile(file, stats)
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
func exitError(err error) {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func writeStats(w io.Writer, sortedStats []stat) int {
|
||||
for i, stat := range sortedStats {
|
||||
if i == *top {
|
||||
return i
|
||||
}
|
||||
if stat.Complexity <= *over {
|
||||
return i
|
||||
}
|
||||
fmt.Fprintln(w, stat)
|
||||
}
|
||||
return len(sortedStats)
|
||||
}
|
||||
|
||||
func showAverage(stats []stat) {
|
||||
fmt.Printf("Average: %.3g\n", average(stats))
|
||||
}
|
||||
|
||||
func average(stats []stat) float64 {
|
||||
total := 0
|
||||
for _, s := range stats {
|
||||
total += s.Complexity
|
||||
}
|
||||
return float64(total) / float64(len(stats))
|
||||
}
|
||||
|
||||
type stat struct {
|
||||
PkgName string
|
||||
FuncName string
|
||||
Complexity int
|
||||
Pos token.Position
|
||||
}
|
||||
|
||||
func (s stat) String() string {
|
||||
return fmt.Sprintf("%d %s %s %s", s.Complexity, s.PkgName, s.FuncName, s.Pos)
|
||||
}
|
||||
|
||||
type byComplexity []stat
|
||||
|
||||
func (s byComplexity) Len() int { return len(s) }
|
||||
func (s byComplexity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s byComplexity) Less(i, j int) bool {
|
||||
return s[i].Complexity >= s[j].Complexity
|
||||
}
|
||||
|
||||
func buildStats(f *ast.File, fset *token.FileSet, stats []stat) []stat {
|
||||
for _, decl := range f.Decls {
|
||||
if fn, ok := decl.(*ast.FuncDecl); ok {
|
||||
stats = append(stats, stat{
|
||||
PkgName: f.Name.Name,
|
||||
FuncName: funcName(fn),
|
||||
Complexity: complexity(fn),
|
||||
Pos: fset.Position(fn.Pos()),
|
||||
})
|
||||
}
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
// funcName returns the name representation of a function or method:
|
||||
// "(Type).Name" for methods or simply "Name" for functions.
|
||||
func funcName(fn *ast.FuncDecl) string {
|
||||
if fn.Recv != nil {
|
||||
typ := fn.Recv.List[0].Type
|
||||
return fmt.Sprintf("(%s).%s", recvString(typ), fn.Name)
|
||||
}
|
||||
return fn.Name.Name
|
||||
}
|
||||
|
||||
// recvString returns a string representation of recv of the
|
||||
// form "T", "*T", or "BADRECV" (if not a proper receiver type).
|
||||
func recvString(recv ast.Expr) string {
|
||||
switch t := recv.(type) {
|
||||
case *ast.Ident:
|
||||
return t.Name
|
||||
case *ast.StarExpr:
|
||||
return "*" + recvString(t.X)
|
||||
}
|
||||
return "BADRECV"
|
||||
}
|
||||
|
||||
// complexity calculates the cyclomatic complexity of a function.
|
||||
func complexity(fn *ast.FuncDecl) int {
|
||||
v := complexityVisitor{}
|
||||
ast.Walk(&v, fn)
|
||||
return v.Complexity
|
||||
}
|
||||
|
||||
type complexityVisitor struct {
|
||||
// Complexity is the cyclomatic complexity
|
||||
Complexity int
|
||||
}
|
||||
|
||||
// Visit implements the ast.Visitor interface.
|
||||
func (v *complexityVisitor) Visit(n ast.Node) ast.Visitor {
|
||||
switch n := n.(type) {
|
||||
case *ast.FuncDecl, *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.CaseClause, *ast.CommClause:
|
||||
v.Complexity++
|
||||
case *ast.BinaryExpr:
|
||||
if n.Op == token.LAND || n.Op == token.LOR {
|
||||
v.Complexity++
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
38
vendor/github.com/fzipp/gocyclo/CHANGELOG.md
generated
vendored
Normal file
38
vendor/github.com/fzipp/gocyclo/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.3.1]
|
||||
### Added
|
||||
- Test coverage
|
||||
|
||||
### Fixed
|
||||
- Fix cyclomatic complexity for function literals (base complexity of 1 was missing)
|
||||
|
||||
## [0.3.0] - 2020-10-17
|
||||
### Added
|
||||
- New `-avg-short` and `-total-short` options for printing average and total cyclomatic complexities without label
|
||||
- Export the `AnalyzeASTFile` function in package API
|
||||
- Doc comments for exported functions and types
|
||||
|
||||
### Fixed
|
||||
- Ignore `default` cases
|
||||
|
||||
## [0.2.0] - 2020-10-17
|
||||
### Added
|
||||
- Support for gocyclo as a package
|
||||
- Support for ignoring of individual functions via a new `gocyclo:ignore` directive
|
||||
- New `-total` option to compute total cyclomatic complexity
|
||||
- New `-ignore` option to ignore files matching a regular expression
|
||||
- Analysis of function literals at declaration level
|
||||
|
||||
### Changed
|
||||
- Breaking: installation changed to `go get github.com/fzipp/gocyclo/cmd/gocyclo`
|
||||
|
||||
## [0.1.0] - 2020-10-17
|
||||
|
||||
### Added
|
||||
- `go.mod` file; beginning of versioning
|
||||
|
||||
7
vendor/github.com/fzipp/gocyclo/CONTRIBUTORS
generated
vendored
Normal file
7
vendor/github.com/fzipp/gocyclo/CONTRIBUTORS
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Names should be added to this file like so:
|
||||
# Name <email address>
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
Frederik Zipp <fzipp@gmx.de>
|
||||
Harshavardhana <harsha@harshavardhana.net>
|
||||
107
vendor/github.com/fzipp/gocyclo/README.md
generated
vendored
Normal file
107
vendor/github.com/fzipp/gocyclo/README.md
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
# gocyclo
|
||||
|
||||
[](https://pkg.go.dev/github.com/fzipp/gocyclo)
|
||||
[](https://goreportcard.com/report/github.com/fzipp/gocyclo)
|
||||
|
||||
Gocyclo calculates
|
||||
[cyclomatic complexities](https://en.wikipedia.org/wiki/Cyclomatic_complexity)
|
||||
of functions in Go source code.
|
||||
|
||||
Cyclomatic complexity is a
|
||||
[code quality metric](https://en.wikipedia.org/wiki/Software_metric)
|
||||
which can be used to identify code that needs refactoring.
|
||||
It measures the number of linearly independent paths through a function's
|
||||
source code.
|
||||
|
||||
The cyclomatic complexity of a function is calculated according to the
|
||||
following rules:
|
||||
|
||||
```
|
||||
1 is the base complexity of a function
|
||||
+1 for each 'if', 'for', 'case', '&&' or '||'
|
||||
```
|
||||
|
||||
A function with a higher cyclomatic complexity requires more test cases to
|
||||
cover all possible paths and is potentially harder to understand. The
|
||||
complexity can be reduced by applying common refactoring techniques that lead
|
||||
to smaller functions.
|
||||
|
||||
## Installation
|
||||
|
||||
To install the `gocyclo` command, run
|
||||
|
||||
```
|
||||
$ go get github.com/fzipp/gocyclo/cmd/gocyclo
|
||||
```
|
||||
|
||||
and put the resulting binary in one of your PATH directories if
|
||||
`$GOPATH/bin` isn't already in your PATH.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
Calculate cyclomatic complexities of Go functions.
|
||||
Usage:
|
||||
gocyclo [flags] <Go file or directory> ...
|
||||
|
||||
Flags:
|
||||
-over N show functions with complexity > N only and
|
||||
return exit code 1 if the set is non-empty
|
||||
-top N show the top N most complex functions only
|
||||
-avg, -avg-short show the average complexity over all functions;
|
||||
the short option prints the value without a label
|
||||
-total, -total-short show the total complexity for all functions;
|
||||
the short option prints the value without a label
|
||||
-ignore REGEX exclude files matching the given regular expression
|
||||
|
||||
The output fields for each line are:
|
||||
<complexity> <package> <function> <file:line:column>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```
|
||||
$ gocyclo .
|
||||
$ gocyclo main.go
|
||||
$ gocyclo -top 10 src/
|
||||
$ gocyclo -over 25 docker
|
||||
$ gocyclo -avg .
|
||||
$ gocyclo -top 20 -ignore "_test|Godeps|vendor/" .
|
||||
$ gocyclo -over 3 -avg gocyclo/
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
```
|
||||
9 gocyclo (*complexityVisitor).Visit complexity.go:30:1
|
||||
8 main main cmd/gocyclo/main.go:53:1
|
||||
7 gocyclo (*fileAnalyzer).analyzeDecl analyze.go:96:1
|
||||
4 gocyclo Analyze analyze.go:24:1
|
||||
4 gocyclo parseDirectives directives.go:27:1
|
||||
4 gocyclo (Stats).SortAndFilter stats.go:52:1
|
||||
Average: 2.72
|
||||
```
|
||||
|
||||
Note that the average is calculated over all analyzed functions,
|
||||
not just the printed ones.
|
||||
|
||||
### Ignoring individual functions
|
||||
|
||||
Individual functions can be ignored with a `gocyclo:ignore` directive:
|
||||
|
||||
```
|
||||
//gocyclo:ignore
|
||||
func f1() {
|
||||
// ...
|
||||
}
|
||||
|
||||
//gocyclo:ignore
|
||||
var f2 = func() {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is free and open source software licensed under the
|
||||
[BSD 3-Clause License](LICENSE).
|
||||
151
vendor/github.com/fzipp/gocyclo/analyze.go
generated
vendored
Normal file
151
vendor/github.com/fzipp/gocyclo/analyze.go
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright 2020 Frederik Zipp. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gocyclo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Analyze calculates the cyclomatic complexities of the functions and methods
|
||||
// in the Go source code files in the given paths. If a path is a directory
|
||||
// all Go files under that directory are analyzed recursively.
|
||||
// Files with paths matching the 'ignore' regular expressions are skipped.
|
||||
// The 'ignore' parameter can be nil, meaning that no files are skipped.
|
||||
func Analyze(paths []string, ignore *regexp.Regexp) Stats {
|
||||
var stats Stats
|
||||
for _, path := range paths {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
log.Printf("could not get file info for path %q: %s\n", path, err)
|
||||
continue
|
||||
}
|
||||
if info.IsDir() {
|
||||
stats = analyzeDir(path, ignore, stats)
|
||||
} else {
|
||||
stats = analyzeFile(path, ignore, stats)
|
||||
}
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
func analyzeDir(dirname string, ignore *regexp.Regexp, stats Stats) Stats {
|
||||
filepath.Walk(dirname, func(path string, info os.FileInfo, err error) error {
|
||||
if err == nil && isGoFile(info) {
|
||||
stats = analyzeFile(path, ignore, stats)
|
||||
}
|
||||
return err
|
||||
})
|
||||
return stats
|
||||
}
|
||||
|
||||
func isGoFile(f os.FileInfo) bool {
|
||||
return !f.IsDir() && strings.HasSuffix(f.Name(), ".go")
|
||||
}
|
||||
|
||||
func analyzeFile(path string, ignore *regexp.Regexp, stats Stats) Stats {
|
||||
if isIgnored(path, ignore) {
|
||||
return stats
|
||||
}
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return AnalyzeASTFile(f, fset, stats)
|
||||
}
|
||||
|
||||
func isIgnored(path string, ignore *regexp.Regexp) bool {
|
||||
return ignore != nil && ignore.MatchString(path)
|
||||
}
|
||||
|
||||
// AnalyzeASTFile calculates the cyclomatic complexities of the functions
|
||||
// and methods in the abstract syntax tree (AST) of a parsed Go file and
|
||||
// appends the results to the given Stats slice.
|
||||
func AnalyzeASTFile(f *ast.File, fs *token.FileSet, s Stats) Stats {
|
||||
analyzer := &fileAnalyzer{
|
||||
file: f,
|
||||
fileSet: fs,
|
||||
stats: s,
|
||||
}
|
||||
return analyzer.analyze()
|
||||
}
|
||||
|
||||
type fileAnalyzer struct {
|
||||
file *ast.File
|
||||
fileSet *token.FileSet
|
||||
stats Stats
|
||||
}
|
||||
|
||||
func (a *fileAnalyzer) analyze() Stats {
|
||||
for _, decl := range a.file.Decls {
|
||||
a.analyzeDecl(decl)
|
||||
}
|
||||
return a.stats
|
||||
}
|
||||
|
||||
func (a *fileAnalyzer) analyzeDecl(d ast.Decl) {
|
||||
switch decl := d.(type) {
|
||||
case *ast.FuncDecl:
|
||||
a.addStatIfNotIgnored(decl, funcName(decl), decl.Doc)
|
||||
case *ast.GenDecl:
|
||||
for _, spec := range decl.Specs {
|
||||
valueSpec, ok := spec.(*ast.ValueSpec)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, value := range valueSpec.Values {
|
||||
funcLit, ok := value.(*ast.FuncLit)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
a.addStatIfNotIgnored(funcLit, valueSpec.Names[0].Name, decl.Doc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *fileAnalyzer) addStatIfNotIgnored(node ast.Node, funcName string, doc *ast.CommentGroup) {
|
||||
if parseDirectives(doc).HasIgnore() {
|
||||
return
|
||||
}
|
||||
a.stats = append(a.stats, Stat{
|
||||
PkgName: a.file.Name.Name,
|
||||
FuncName: funcName,
|
||||
Complexity: Complexity(node),
|
||||
Pos: a.fileSet.Position(node.Pos()),
|
||||
})
|
||||
}
|
||||
|
||||
// funcName returns the name representation of a function or method:
|
||||
// "(Type).Name" for methods or simply "Name" for functions.
|
||||
func funcName(fn *ast.FuncDecl) string {
|
||||
if fn.Recv != nil {
|
||||
if fn.Recv.NumFields() > 0 {
|
||||
typ := fn.Recv.List[0].Type
|
||||
return fmt.Sprintf("(%s).%s", recvString(typ), fn.Name)
|
||||
}
|
||||
}
|
||||
return fn.Name.Name
|
||||
}
|
||||
|
||||
// recvString returns a string representation of recv of the
|
||||
// form "T", "*T", or "BADRECV" (if not a proper receiver type).
|
||||
func recvString(recv ast.Expr) string {
|
||||
switch t := recv.(type) {
|
||||
case *ast.Ident:
|
||||
return t.Name
|
||||
case *ast.StarExpr:
|
||||
return "*" + recvString(t.X)
|
||||
}
|
||||
return "BADRECV"
|
||||
}
|
||||
121
vendor/github.com/fzipp/gocyclo/cmd/gocyclo/main.go
generated
vendored
Normal file
121
vendor/github.com/fzipp/gocyclo/cmd/gocyclo/main.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
// Copyright 2013 Frederik Zipp. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Gocyclo calculates the cyclomatic complexities of functions and
|
||||
// methods in Go source code.
|
||||
//
|
||||
// Usage:
|
||||
// gocyclo [<flag> ...] <Go file or directory> ...
|
||||
//
|
||||
// Flags:
|
||||
// -over N show functions with complexity > N only and
|
||||
// return exit code 1 if the output is non-empty
|
||||
// -top N show the top N most complex functions only
|
||||
// -avg, -avg-short show the average complexity;
|
||||
// the short option prints the value without a label
|
||||
// -total, -total-short show the total complexity;
|
||||
// the short option prints the value without a label
|
||||
// -ignore REGEX exclude files matching the given regular expression
|
||||
//
|
||||
// The output fields for each line are:
|
||||
// <complexity> <package> <function> <file:line:column>
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"github.com/fzipp/gocyclo"
|
||||
)
|
||||
|
||||
const usageDoc = `Calculate cyclomatic complexities of Go functions.
|
||||
Usage:
|
||||
gocyclo [flags] <Go file or directory> ...
|
||||
|
||||
Flags:
|
||||
-over N show functions with complexity > N only and
|
||||
return exit code 1 if the set is non-empty
|
||||
-top N show the top N most complex functions only
|
||||
-avg, -avg-short show the average complexity over all functions;
|
||||
the short option prints the value without a label
|
||||
-total, -total-short show the total complexity for all functions;
|
||||
the short option prints the value without a label
|
||||
-ignore REGEX exclude files matching the given regular expression
|
||||
|
||||
The output fields for each line are:
|
||||
<complexity> <package> <function> <file:line:column>
|
||||
`
|
||||
|
||||
func main() {
|
||||
over := flag.Int("over", 0, "show functions with complexity > N only")
|
||||
top := flag.Int("top", -1, "show the top N most complex functions only")
|
||||
avg := flag.Bool("avg", false, "show the average complexity")
|
||||
avgShort := flag.Bool("avg-short", false, "show the average complexity without a label")
|
||||
total := flag.Bool("total", false, "show the total complexity")
|
||||
totalShort := flag.Bool("total-short", false, "show the total complexity without a label")
|
||||
ignore := flag.String("ignore", "", "exclude files matching the given regular expression")
|
||||
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("gocyclo: ")
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
paths := flag.Args()
|
||||
if len(paths) == 0 {
|
||||
usage()
|
||||
}
|
||||
|
||||
allStats := gocyclo.Analyze(paths, regex(*ignore))
|
||||
shownStats := allStats.SortAndFilter(*top, *over)
|
||||
|
||||
printStats(shownStats)
|
||||
if *avg || *avgShort {
|
||||
printAverage(allStats, *avgShort)
|
||||
}
|
||||
if *total || *totalShort {
|
||||
printTotal(allStats, *totalShort)
|
||||
}
|
||||
|
||||
if *over > 0 && len(shownStats) > 0 {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func regex(expr string) *regexp.Regexp {
|
||||
if expr == "" {
|
||||
return nil
|
||||
}
|
||||
re, err := regexp.Compile(expr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return re
|
||||
}
|
||||
|
||||
func printStats(s gocyclo.Stats) {
|
||||
for _, stat := range s {
|
||||
fmt.Println(stat)
|
||||
}
|
||||
}
|
||||
|
||||
func printAverage(s gocyclo.Stats, short bool) {
|
||||
if !short {
|
||||
fmt.Print("Average: ")
|
||||
}
|
||||
fmt.Printf("%.3g\n", s.AverageComplexity())
|
||||
}
|
||||
|
||||
func printTotal(s gocyclo.Stats, short bool) {
|
||||
if !short {
|
||||
fmt.Print("Total: ")
|
||||
}
|
||||
fmt.Printf("%d\n", s.TotalComplexity())
|
||||
}
|
||||
|
||||
func usage() {
|
||||
_, _ = fmt.Fprintf(os.Stderr, usageDoc)
|
||||
os.Exit(2)
|
||||
}
|
||||
48
vendor/github.com/fzipp/gocyclo/complexity.go
generated
vendored
Normal file
48
vendor/github.com/fzipp/gocyclo/complexity.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2020 Frederik Zipp. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gocyclo calculates the cyclomatic complexities of functions and
|
||||
// methods in Go source code.
|
||||
package gocyclo
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
)
|
||||
|
||||
// Complexity calculates the cyclomatic complexity of a function.
|
||||
// The 'fn' node is either a *ast.FuncDecl or a *ast.FuncLit.
|
||||
func Complexity(fn ast.Node) int {
|
||||
v := complexityVisitor{
|
||||
complexity: 1,
|
||||
}
|
||||
ast.Walk(&v, fn)
|
||||
return v.complexity
|
||||
}
|
||||
|
||||
type complexityVisitor struct {
|
||||
// complexity is the cyclomatic complexity
|
||||
complexity int
|
||||
}
|
||||
|
||||
// Visit implements the ast.Visitor interface.
|
||||
func (v *complexityVisitor) Visit(n ast.Node) ast.Visitor {
|
||||
switch n := n.(type) {
|
||||
case *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt:
|
||||
v.complexity++
|
||||
case *ast.CaseClause:
|
||||
if n.List != nil { // ignore default case
|
||||
v.complexity++
|
||||
}
|
||||
case *ast.CommClause:
|
||||
if n.Comm != nil { // ignore default case
|
||||
v.complexity++
|
||||
}
|
||||
case *ast.BinaryExpr:
|
||||
if n.Op == token.LAND || n.Op == token.LOR {
|
||||
v.complexity++
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
39
vendor/github.com/fzipp/gocyclo/directives.go
generated
vendored
Normal file
39
vendor/github.com/fzipp/gocyclo/directives.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2020 Frederik Zipp. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gocyclo
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type directives []string
|
||||
|
||||
func (ds directives) HasIgnore() bool {
|
||||
return ds.isPresent("ignore")
|
||||
}
|
||||
|
||||
func (ds directives) isPresent(name string) bool {
|
||||
for _, d := range ds {
|
||||
if d == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func parseDirectives(doc *ast.CommentGroup) directives {
|
||||
if doc == nil {
|
||||
return directives{}
|
||||
}
|
||||
const prefix = "//gocyclo:"
|
||||
var ds directives
|
||||
for _, comment := range doc.List {
|
||||
if strings.HasPrefix(comment.Text, prefix) {
|
||||
ds = append(ds, strings.TrimSpace(strings.TrimPrefix(comment.Text, prefix)))
|
||||
}
|
||||
}
|
||||
return ds
|
||||
}
|
||||
3
vendor/github.com/fzipp/gocyclo/go.mod
generated
vendored
Normal file
3
vendor/github.com/fzipp/gocyclo/go.mod
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module github.com/fzipp/gocyclo
|
||||
|
||||
go 1.15
|
||||
73
vendor/github.com/fzipp/gocyclo/stats.go
generated
vendored
Normal file
73
vendor/github.com/fzipp/gocyclo/stats.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2020 Frederik Zipp. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gocyclo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Stat holds the cyclomatic complexity of a function, along with its package
|
||||
// and and function name and its position in the source code.
|
||||
type Stat struct {
|
||||
PkgName string
|
||||
FuncName string
|
||||
Complexity int
|
||||
Pos token.Position
|
||||
}
|
||||
|
||||
// String formats the cyclomatic complexity information of a function in
|
||||
// the following format: "<complexity> <package> <function> <file:line:column>"
|
||||
func (s Stat) String() string {
|
||||
return fmt.Sprintf("%d %s %s %s", s.Complexity, s.PkgName, s.FuncName, s.Pos)
|
||||
}
|
||||
|
||||
// Stats hold the cyclomatic complexities of many functions.
|
||||
type Stats []Stat
|
||||
|
||||
// AverageComplexity calculates the average cyclomatic complexity of the
|
||||
// cyclomatic complexities in s.
|
||||
func (s Stats) AverageComplexity() float64 {
|
||||
return float64(s.TotalComplexity()) / float64(len(s))
|
||||
}
|
||||
|
||||
// TotalComplexity calculates the total sum of all cyclomatic
|
||||
// complexities in s.
|
||||
func (s Stats) TotalComplexity() uint64 {
|
||||
total := uint64(0)
|
||||
for _, stat := range s {
|
||||
total += uint64(stat.Complexity)
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// SortAndFilter sorts the cyclomatic complexities in s in descending order
|
||||
// and returns a slice of s limited to the 'top' N entries with a cyclomatic
|
||||
// complexity greater than 'over'. If 'top' is negative, i.e. -1, it does
|
||||
// not limit the result. If 'over' is <= 0 it does not limit the result either,
|
||||
// because a function has a base cyclomatic complexity of at least 1.
|
||||
func (s Stats) SortAndFilter(top, over int) Stats {
|
||||
result := make(Stats, len(s))
|
||||
copy(result, s)
|
||||
sort.Sort(byComplexityDesc(result))
|
||||
for i, stat := range result {
|
||||
if i == top {
|
||||
return result[:i]
|
||||
}
|
||||
if stat.Complexity <= over {
|
||||
return result[:i]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type byComplexityDesc Stats
|
||||
|
||||
func (s byComplexityDesc) Len() int { return len(s) }
|
||||
func (s byComplexityDesc) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s byComplexityDesc) Less(i, j int) bool {
|
||||
return s[i].Complexity >= s[j].Complexity
|
||||
}
|
||||
7
vendor/modules.txt
vendored
7
vendor/modules.txt
vendored
@@ -3,9 +3,6 @@ github.com/BurntSushi/toml
|
||||
# github.com/DataDog/zstd v1.4.8
|
||||
## explicit
|
||||
github.com/DataDog/zstd
|
||||
# github.com/alecthomas/gocyclo v0.0.0-20150208221726-aa8f8b160214
|
||||
## explicit
|
||||
github.com/alecthomas/gocyclo
|
||||
# github.com/alecthomas/gometalinter v1.0.3
|
||||
## explicit
|
||||
github.com/alecthomas/gometalinter
|
||||
@@ -44,6 +41,10 @@ github.com/dgryski/go-farm
|
||||
# github.com/dustin/go-humanize v1.0.0
|
||||
## explicit
|
||||
github.com/dustin/go-humanize
|
||||
# github.com/fzipp/gocyclo v0.3.1
|
||||
## explicit
|
||||
github.com/fzipp/gocyclo
|
||||
github.com/fzipp/gocyclo/cmd/gocyclo
|
||||
# github.com/golang/protobuf v1.5.2
|
||||
## explicit
|
||||
github.com/golang/protobuf/proto
|
||||
|
||||
Reference in New Issue
Block a user