-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
115 lines (92 loc) · 2.11 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package main
import (
"fmt"
"go/build"
"os"
"path"
"sort"
"strings"
"golang.org/x/mod/modfile"
)
func pkgImports(module, root, dir string) ([]string, error) {
pkg, err := build.ImportDir(path.Join(root, dir), 0)
if err != nil {
if _, nogo := err.(*build.NoGoError); nogo {
return nil, nil
}
return nil, err
}
imports := []string{}
for _, i := range pkg.Imports {
if strings.HasPrefix(i, module) {
imports = append(imports, strings.TrimPrefix(i, module))
}
}
return imports, nil
}
func scanDir(module, root, dir string) (map[string][]string, error) {
deps, err := pkgImports(module, root, dir)
if err != nil {
return nil, err
}
result := map[string][]string{dir: deps}
entries, err := os.ReadDir(path.Join(root, dir))
if err != nil {
return nil, err
}
for _, e := range entries {
if !e.IsDir() ||
e.Name() == "vendor" ||
e.Name() == "testdata" ||
strings.HasPrefix(e.Name(), ".") ||
strings.HasSuffix(e.Name(), "test") {
continue
}
imports, err := scanDir(module, root, path.Join(dir, e.Name()))
if err != nil {
return nil, err
}
for k, v := range imports {
if _, exists := result[k]; exists {
return nil, fmt.Errorf("duplicate package %q in dir %q", k, dir)
}
result[k] = v
}
}
return result, nil
}
func importMap(root string) (map[string][]string, error) {
mod, err := os.ReadFile(path.Join(root, "go.mod"))
if err != nil {
return nil, err
}
return scanDir(modfile.ModulePath(mod)+"/", root, "")
}
func outputGraphviz(imports map[string][]string) {
fmt.Println("digraph G {")
pkgs := make([]string, 0, len(imports))
for pkg := range imports {
pkgs = append(pkgs, pkg)
}
sort.Strings(pkgs)
for _, pkg := range pkgs {
deps := imports[pkg]
sort.Strings(deps)
for _, dep := range deps {
fmt.Printf("\t%q -> %q\n", pkg, dep)
}
}
fmt.Println("}")
}
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: godeps <path to root of go module checkout>")
os.Exit(1)
}
imports, err := importMap(os.Args[1])
if err != nil {
fmt.Printf("Failed to compute import map: %s", err)
os.Exit(1)
}
outputGraphviz(imports)
}