...
Source file src/cmd/doc/dirs.go
1
2
3
4
5 package main
6
7 import (
8 "bytes"
9 "log"
10 "os"
11 "os/exec"
12 "path/filepath"
13 "strings"
14 "sync"
15 )
16
17
18
19 type Dir struct {
20 importPath string
21 dir string
22 }
23
24
25
26
27
28 type Dirs struct {
29 scan chan Dir
30 hist []Dir
31 offset int
32 }
33
34 var dirs Dirs
35
36
37
38 func dirsInit(extra ...Dir) {
39 dirs.hist = make([]Dir, 0, 1000)
40 dirs.hist = append(dirs.hist, extra...)
41 dirs.scan = make(chan Dir)
42 go dirs.walk(codeRoots())
43 }
44
45
46 func (d *Dirs) Reset() {
47 d.offset = 0
48 }
49
50
51
52 func (d *Dirs) Next() (Dir, bool) {
53 if d.offset < len(d.hist) {
54 dir := d.hist[d.offset]
55 d.offset++
56 return dir, true
57 }
58 dir, ok := <-d.scan
59 if !ok {
60 return Dir{}, false
61 }
62 d.hist = append(d.hist, dir)
63 d.offset++
64 return dir, ok
65 }
66
67
68 func (d *Dirs) walk(roots []Dir) {
69 for _, root := range roots {
70 d.bfsWalkRoot(root)
71 }
72 close(d.scan)
73 }
74
75
76
77 func (d *Dirs) bfsWalkRoot(root Dir) {
78 root.dir = filepath.Clean(root.dir)
79
80
81 this := []string{}
82
83 next := []string{root.dir}
84
85 for len(next) > 0 {
86 this, next = next, this[0:0]
87 for _, dir := range this {
88 fd, err := os.Open(dir)
89 if err != nil {
90 log.Print(err)
91 continue
92 }
93 entries, err := fd.Readdir(0)
94 fd.Close()
95 if err != nil {
96 log.Print(err)
97 continue
98 }
99 hasGoFiles := false
100 for _, entry := range entries {
101 name := entry.Name()
102
103
104 if !entry.IsDir() {
105 if !hasGoFiles && strings.HasSuffix(name, ".go") {
106 hasGoFiles = true
107 }
108 continue
109 }
110
111
112
113 if name[0] == '.' || name[0] == '_' || name == "testdata" {
114 continue
115 }
116
117 if usingModules && name == "vendor" {
118 continue
119 }
120
121 next = append(next, filepath.Join(dir, name))
122 }
123 if hasGoFiles {
124
125 importPath := root.importPath
126 if len(dir) > len(root.dir) {
127 if importPath != "" {
128 importPath += "/"
129 }
130 importPath += filepath.ToSlash(dir[len(root.dir)+1:])
131 }
132 d.scan <- Dir{importPath, dir}
133 }
134 }
135
136 }
137 }
138
139 var testGOPATH = false
140
141
142
143
144 func codeRoots() []Dir {
145 codeRootsCache.once.Do(func() {
146 codeRootsCache.roots = findCodeRoots()
147 })
148 return codeRootsCache.roots
149 }
150
151 var codeRootsCache struct {
152 once sync.Once
153 roots []Dir
154 }
155
156 var usingModules bool
157
158 func findCodeRoots() []Dir {
159 list := []Dir{{"", filepath.Join(buildCtx.GOROOT, "src")}}
160
161 if !testGOPATH {
162
163
164 stdout, _ := exec.Command("go", "env", "GOMOD").Output()
165 usingModules = len(bytes.TrimSpace(stdout)) > 0
166 }
167
168 if !usingModules {
169 for _, root := range splitGopath() {
170 list = append(list, Dir{"", filepath.Join(root, "src")})
171 }
172 return list
173 }
174
175
176
177
178
179
180 cmd := exec.Command("go", "list", "-m", "-f={{.Path}}\t{{.Dir}}", "all")
181 cmd.Stderr = os.Stderr
182 out, _ := cmd.Output()
183 for _, line := range strings.Split(string(out), "\n") {
184 i := strings.Index(line, "\t")
185 if i < 0 {
186 continue
187 }
188 path, dir := line[:i], line[i+1:]
189 if dir != "" {
190 list = append(list, Dir{path, dir})
191 }
192 }
193
194 return list
195 }
196
View as plain text