-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
yuanyou
committed
Nov 28, 2022
0 parents
commit d4470a1
Showing
12 changed files
with
553 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# go-cyclic | ||
|
||
<h4> Go 循环依赖检测工具 </h4> | ||
|
||
快速开始 | ||
=============== | ||
```bash | ||
go install github.com/elza2/go-cyclic@latest | ||
# path 路径要设置为 go.mod 文件所在的全路径. | ||
go-cyclic gocyclic --dir .path | ||
``` | ||
|
||
运行测试 | ||
=============== | ||
```bash | ||
git | ||
go run ./cmd/main.go gocyclic --dir .path | ||
``` | ||
|
||
```bash | ||
# success output. | ||
Success. Not circular dependence. | ||
|
||
# failed output. | ||
┌---→ daji.go | ||
┆ ↓ | ||
┆ routes.go | ||
┆ ↓ | ||
└--- handler.go | ||
``` | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package actions | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
"go-cyclic/tool" | ||
"log" | ||
) | ||
|
||
func RunCyclic(cmd *cobra.Command, args []string) { | ||
dir, err := cmd.Flags().GetString("dir") | ||
if err != nil { | ||
log.Fatalf("get dir params failed: %v\n", err) | ||
} | ||
if err = tool.CheckCycleDepend(dir); err != nil { | ||
log.Fatalf("run failed: %v\n", err) | ||
} | ||
} | ||
|
||
func init() { | ||
cmd := &cobra.Command{ | ||
Use: "gocyclic", | ||
Run: RunCyclic, | ||
} | ||
rootCmd.AddCommand(cmd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package actions | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
"log" | ||
"os" | ||
) | ||
|
||
const Service = "go-cyclic" | ||
|
||
var ( | ||
rootCmd = &cobra.Command{Use: Service} | ||
) | ||
|
||
func Execute() { | ||
if err := rootCmd.Execute(); err != nil { | ||
log.Println(err) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func init() { | ||
rootCmd.PersistentFlags().String("dir", os.Getenv("dir"), "dir. eg: full path of the go.mod file") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package main | ||
|
||
import ( | ||
"go-cyclic/cmd/actions" | ||
) | ||
|
||
func main() { | ||
actions.Execute() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package errors | ||
|
||
import "errors" | ||
|
||
var ( | ||
GoModNotExist = errors.New("not find go.mod file") | ||
GoModParseFailed = errors.New("go.mod file parse failed") | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package main | ||
|
||
import ( | ||
"go-cyclic/tool" | ||
"testing" | ||
) | ||
|
||
func TestCyclic(t *testing.T) { | ||
tool.CheckCycleDepend("/Users/yuanyou/go/src/daji") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module go-cyclic | ||
|
||
go 1.18 | ||
|
||
require ( | ||
github.com/fatih/color v1.13.0 // indirect | ||
github.com/inconshreveable/mousetrap v1.0.1 // indirect | ||
github.com/mattn/go-colorable v0.1.9 // indirect | ||
github.com/mattn/go-isatty v0.0.14 // indirect | ||
github.com/spf13/cobra v1.6.1 // indirect | ||
github.com/spf13/pflag v1.0.5 // indirect | ||
golang.org/x/mod v0.7.0 // indirect | ||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= | ||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= | ||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= | ||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= | ||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= | ||
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= | ||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= | ||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= | ||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= | ||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= | ||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= | ||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= | ||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= | ||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= | ||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= | ||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | ||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= | ||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package resolver | ||
|
||
import ( | ||
"fmt" | ||
"go-cyclic/errors" | ||
"go-cyclic/sprite" | ||
"go/parser" | ||
"go/token" | ||
"golang.org/x/mod/modfile" | ||
"io/ioutil" | ||
"strings" | ||
) | ||
|
||
var ( | ||
GoMod = "go.mod" | ||
|
||
fset = token.NewFileSet() | ||
) | ||
|
||
// ParseDir parse path. | ||
func ParseDir(dir string) string { | ||
idx := strings.LastIndex(dir, "/") | ||
if idx == -1 { | ||
return dir | ||
} | ||
return dir[idx+1:] | ||
} | ||
|
||
func ParseGoModule(dir string) (moduleName string, err error) { | ||
readFile, err := ioutil.ReadFile(dir + "/" + GoMod) | ||
if err != nil { | ||
return "", errors.GoModNotExist | ||
} | ||
modFile, err := modfile.Parse(GoMod, readFile, nil) | ||
if err != nil { | ||
return "", errors.GoModParseFailed | ||
} | ||
return modFile.Module.Mod.Path, nil | ||
} | ||
|
||
func ParseNodeSprite(root string, module string, dir string) (nodes []*sprite.NodeSprite, err error) { | ||
nodeSprites := make([]*sprite.NodeSprite, 0) | ||
files, err := ioutil.ReadDir(dir) | ||
if err != nil { | ||
return nil, err | ||
} | ||
parseDir, err := parser.ParseDir(fset, dir, nil, 0) | ||
if err != nil { | ||
return nodeSprites, err | ||
} | ||
for k, v := range parseDir { | ||
nodeImports := map[string][]string{} | ||
for key, value := range v.Files { | ||
for _, port := range value.Imports { | ||
nodeImports[key] = append(nodeImports[key], port.Path.Value[1:len(port.Path.Value)-1]) | ||
} | ||
filePath, nodeName := GetNodeSpritePathName(key) | ||
nodeSprites = append(nodeSprites, &sprite.NodeSprite{ | ||
FilePath: filePath, | ||
RootName: root, | ||
ModuleName: module, | ||
PackageName: k, | ||
NodeName: nodeName, | ||
ImportNames: nodeImports[key], | ||
}) | ||
} | ||
} | ||
for _, file := range files { | ||
if file.IsDir() { | ||
sprites, err := ParseNodeSprite(root, module, fmt.Sprintf("%s/%s", dir, file.Name())) | ||
if err != nil { | ||
return sprites, err | ||
} | ||
nodeSprites = append(nodeSprites, sprites...) | ||
} | ||
} | ||
return nodeSprites, nil | ||
} | ||
|
||
func GetNodeSpritePathName(content string) (filePath, nodeName string) { | ||
contains := strings.Contains(content, "/") | ||
if !contains { | ||
return content, content | ||
} | ||
index := strings.LastIndex(content, "/") | ||
return content[:index], content[index+1:] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package sprite | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
type NodeSprites struct { | ||
nodeSprites []*NodeSprite | ||
} | ||
|
||
func (nodes *NodeSprites) SetNodeSprites(sprites []*NodeSprite) { | ||
nodes.nodeSprites = sprites | ||
} | ||
|
||
func (nodes *NodeSprites) GetNodeSprites() []*NodeSprite { | ||
return nodes.nodeSprites | ||
} | ||
|
||
type NodeSprite struct { | ||
// full file path. | ||
FilePath string | ||
// root name. | ||
RootName string | ||
// module name. | ||
ModuleName string | ||
// package name. | ||
PackageName string | ||
// node name. | ||
NodeName string | ||
// import names. | ||
ImportNames []string | ||
} | ||
|
||
// MatchImportNodeSprite matches the specified sprite. | ||
func (nodes *NodeSprites) MatchImportNodeSprite(match string) []*NodeSprite { | ||
nodeSprites := make([]*NodeSprite, 0) | ||
for _, sprite := range nodes.nodeSprites { | ||
path := sprite.GetRootPath() | ||
if path == match { | ||
nodeSprites = append(nodeSprites, sprite) | ||
} | ||
} | ||
return nodeSprites | ||
} | ||
|
||
func (nodes *NodeSprites) GetNodeSprite(allPath string) *NodeSprite { | ||
for _, sprite := range nodes.nodeSprites { | ||
if sprite.GetAllPath() == allPath { | ||
return sprite | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (node *NodeSprite) GetFilePath() string { | ||
return node.FilePath | ||
} | ||
|
||
func (node *NodeSprite) GetAllPath() string { | ||
return fmt.Sprintf("%s/%s", node.FilePath, node.NodeName) | ||
} | ||
|
||
func (node *NodeSprite) GetRootName() string { | ||
return node.RootName | ||
} | ||
|
||
func (node *NodeSprite) GetRootPath() string { | ||
idx := strings.LastIndex(node.FilePath, "/"+node.RootName) | ||
if idx == -1 { | ||
return node.FilePath | ||
} | ||
return node.ModuleName + node.FilePath[idx+len(node.RootName)+1:] | ||
} | ||
|
||
func (node *NodeSprite) GetImportNames() []string { | ||
return node.ImportNames | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package tool | ||
|
||
import ( | ||
"go-cyclic/resolver" | ||
"go-cyclic/sprite" | ||
"go-cyclic/topology" | ||
) | ||
|
||
func CheckCycleDepend(dir string) error { | ||
// parse root path. | ||
root := resolver.ParseDir(dir) | ||
// parse module name. | ||
module, err := resolver.ParseGoModule(dir) | ||
if err != nil { | ||
return err | ||
} | ||
// parse sprite nodes by path. | ||
sprites, err := resolver.ParseNodeSprite(root, module, dir) | ||
if err != nil { | ||
return err | ||
} | ||
nodeSprites := new(sprite.NodeSprites) | ||
nodeSprites.SetNodeSprites(sprites) | ||
// constructor topology struct. | ||
topologies := topology.ConstructorTopology(nodeSprites) | ||
// check cycle depend. | ||
hasCycle := topologies.CycleDepend() | ||
// print cycle depend. | ||
topologies.PrintCycleDepend(hasCycle) | ||
return nil | ||
} |
Oops, something went wrong.