...
1
2
3
4
5
6
7
8
9
10 package buildutil
11
12 import (
13 "go/build"
14 "os"
15 "path/filepath"
16 "sort"
17 "strings"
18 "sync"
19 )
20
21
22
23
24
25
26
27
28
29
30
31 func AllPackages(ctxt *build.Context) []string {
32 var list []string
33 ForEachPackage(ctxt, func(pkg string, _ error) {
34 list = append(list, pkg)
35 })
36 sort.Strings(list)
37 return list
38 }
39
40
41
42
43
44
45
46
47
48
49
50 func ForEachPackage(ctxt *build.Context, found func(importPath string, err error)) {
51 ch := make(chan item)
52
53 var wg sync.WaitGroup
54 for _, root := range ctxt.SrcDirs() {
55 root := root
56 wg.Add(1)
57 go func() {
58 allPackages(ctxt, root, ch)
59 wg.Done()
60 }()
61 }
62 go func() {
63 wg.Wait()
64 close(ch)
65 }()
66
67
68 for i := range ch {
69 found(i.importPath, i.err)
70 }
71 }
72
73 type item struct {
74 importPath string
75 err error
76 }
77
78
79
80 var ioLimit = make(chan bool, 20)
81
82 func allPackages(ctxt *build.Context, root string, ch chan<- item) {
83 root = filepath.Clean(root) + string(os.PathSeparator)
84
85 var wg sync.WaitGroup
86
87 var walkDir func(dir string)
88 walkDir = func(dir string) {
89
90 base := filepath.Base(dir)
91 if base == "" || base[0] == '.' || base[0] == '_' || base == "testdata" {
92 return
93 }
94
95 pkg := filepath.ToSlash(strings.TrimPrefix(dir, root))
96
97
98 switch pkg {
99 case "builtin":
100 return
101 }
102
103 ioLimit <- true
104 files, err := ReadDir(ctxt, dir)
105 <-ioLimit
106 if pkg != "" || err != nil {
107 ch <- item{pkg, err}
108 }
109 for _, fi := range files {
110 fi := fi
111 if fi.IsDir() {
112 wg.Add(1)
113 go func() {
114 walkDir(filepath.Join(dir, fi.Name()))
115 wg.Done()
116 }()
117 }
118 }
119 }
120
121 walkDir(root)
122 wg.Wait()
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 func ExpandPatterns(ctxt *build.Context, patterns []string) map[string]bool {
141
142
143
144
145
146 pkgs := make(map[string]bool)
147 doPkg := func(pkg string, neg bool) {
148 if neg {
149 delete(pkgs, pkg)
150 } else {
151 pkgs[pkg] = true
152 }
153 }
154
155
156
157 var all []string
158 for _, arg := range patterns {
159 if strings.HasSuffix(arg, "...") {
160 all = AllPackages(ctxt)
161 break
162 }
163 }
164
165 for _, arg := range patterns {
166 if arg == "" {
167 continue
168 }
169
170 neg := arg[0] == '-'
171 if neg {
172 arg = arg[1:]
173 }
174
175 if arg == "..." {
176
177 for _, pkg := range all {
178 doPkg(pkg, neg)
179 }
180 } else if dir := strings.TrimSuffix(arg, "/..."); dir != arg {
181
182 for _, pkg := range all {
183 if strings.HasPrefix(pkg, dir) &&
184 (len(pkg) == len(dir) || pkg[len(dir)] == '/') {
185 doPkg(pkg, neg)
186 }
187 }
188 } else {
189
190 doPkg(strings.TrimSuffix(arg, "/"), neg)
191 }
192 }
193
194 return pkgs
195 }
196
View as plain text