1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package main
16
17 import (
18 "bytes"
19 "encoding/json"
20 "flag"
21 "fmt"
22 "go/build"
23 "os"
24 "path/filepath"
25 "strings"
26 )
27
28
29 type flatPackagesError struct {
30 Pos string
31 Msg string
32 Kind flatPackagesErrorKind
33 }
34
35 type flatPackagesErrorKind int
36
37 const (
38 UnknownError flatPackagesErrorKind = iota
39 ListError
40 ParseError
41 TypeError
42 )
43
44 func (err flatPackagesError) Error() string {
45 pos := err.Pos
46 if pos == "" {
47 pos = "-"
48 }
49 return pos + ": " + err.Msg
50 }
51
52
53
54 type flatPackage struct {
55 ID string
56 Name string `json:",omitempty"`
57 PkgPath string `json:",omitempty"`
58 Standard bool `json:",omitempty"`
59 Errors []flatPackagesError `json:",omitempty"`
60 GoFiles []string `json:",omitempty"`
61 CompiledGoFiles []string `json:",omitempty"`
62 OtherFiles []string `json:",omitempty"`
63 ExportFile string `json:",omitempty"`
64 Imports map[string]string `json:",omitempty"`
65 }
66
67 type goListPackage struct {
68 Dir string
69 ImportPath string
70 Name string
71 Target string
72 Goroot bool
73 Standard bool
74 Root string
75 Export string
76
77 GoFiles []string
78 CgoFiles []string
79 CompiledGoFiles []string
80 IgnoredGoFiles []string
81 IgnoredOtherFiles []string
82 CFiles []string
83 CXXFiles []string
84 MFiles []string
85 HFiles []string
86 FFiles []string
87 SFiles []string
88 SwigFiles []string
89 SwigCXXFiles []string
90 SysoFiles []string
91 TestGoFiles []string
92 XTestGoFiles []string
93
94 EmbedPatterns []string
95 EmbedFiles []string
96 TestEmbedPatterns []string
97 TestEmbedFiles []string
98 XTestEmbedPatterns []string
99 XTestEmbedFiles []string
100
101 Imports []string
102 ImportMap map[string]string
103
104 Incomplete bool
105 Error *flatPackagesError
106 DepsErrors []*flatPackagesError
107 }
108
109 var rulesGoStdlibPrefix string
110
111 func init() {
112 if rulesGoStdlibPrefix == "" {
113 panic("rulesGoStdlibPrefix should have been set via -X")
114 }
115 }
116
117 func stdlibPackageID(importPath string) string {
118 return rulesGoStdlibPrefix + importPath
119 }
120
121
122 func outputBasePath(cloneBase, p string) string {
123 dir, _ := filepath.Rel(cloneBase, p)
124 return filepath.Join("__BAZEL_OUTPUT_BASE__", dir)
125 }
126
127
128
129 func absoluteSourcesPaths(cloneBase, pkgDir string, srcs []string) []string {
130 ret := make([]string, 0, len(srcs))
131 pkgDir = outputBasePath(cloneBase, pkgDir)
132 for _, src := range srcs {
133 absPath := src
134
135
136
137 if !filepath.IsAbs(src) {
138 absPath = filepath.Join(pkgDir, src)
139 }
140
141 ret = append(ret, absPath)
142 }
143 return ret
144 }
145
146
147
148
149
150 func filterGoFiles(srcs []string, pathReplaceFn func(p string) string) []string {
151 ret := make([]string, 0, len(srcs))
152 for _, f := range srcs {
153 if ext := filepath.Ext(f); ext == ".go" || ext == "" {
154 ret = append(ret, pathReplaceFn(f))
155 }
156 }
157
158 return ret
159 }
160
161 func flatPackageForStd(cloneBase string, pkg *goListPackage, pathReplaceFn func(p string) string) *flatPackage {
162 goFiles := absoluteSourcesPaths(cloneBase, pkg.Dir, pkg.GoFiles)
163 compiledGoFiles := absoluteSourcesPaths(cloneBase, pkg.Dir, pkg.CompiledGoFiles)
164
165 newPkg := &flatPackage{
166 ID: stdlibPackageID(pkg.ImportPath),
167 Name: pkg.Name,
168 PkgPath: pkg.ImportPath,
169 ExportFile: outputBasePath(cloneBase, pkg.Target),
170 Imports: map[string]string{},
171 Standard: pkg.Standard,
172 GoFiles: goFiles,
173 CompiledGoFiles: filterGoFiles(compiledGoFiles, pathReplaceFn),
174 }
175
176
177
178
179
180 ids := make(map[string]struct{})
181 for _, id := range pkg.Imports {
182 ids[id] = struct{}{}
183 }
184
185 for path, id := range pkg.ImportMap {
186 newPkg.Imports[path] = stdlibPackageID(id)
187 delete(ids, id)
188 }
189
190 for id := range ids {
191 if id != "C" {
192 newPkg.Imports[id] = stdlibPackageID(id)
193 }
194 }
195
196 return newPkg
197 }
198
199
200 func stdliblist(args []string) error {
201
202 flags := flag.NewFlagSet("stdliblist", flag.ExitOnError)
203 goenv := envFlags(flags)
204 out := flags.String("out", "", "Path to output go list json")
205 cachePath := flags.String("cache", "", "Path to use for GOCACHE")
206 if err := flags.Parse(args); err != nil {
207 return err
208 }
209 if err := goenv.checkFlags(); err != nil {
210 return err
211 }
212
213 if filepath.IsAbs(goenv.sdk) {
214 return fmt.Errorf("-sdk needs to be a relative path, but got %s", goenv.sdk)
215 }
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233 cloneBase, cleanup, err := goenv.workDir()
234 if err != nil {
235 return err
236 }
237 defer func() { cleanup() }()
238
239 newGoRoot := filepath.Join(cloneBase, goenv.sdk)
240 if err := replicate(abs(goenv.sdk), abs(newGoRoot), replicatePaths("src", "pkg/tool", "pkg/include")); err != nil {
241 return err
242 }
243
244
245 absPaths := []string{}
246 for _, path := range filepath.SplitList(os.Getenv("PATH")) {
247 absPaths = append(absPaths, abs(path))
248 }
249 os.Setenv("PATH", strings.Join(absPaths, string(os.PathListSeparator)))
250 os.Setenv("GOROOT", newGoRoot)
251
252 cgoEnabled := os.Getenv("CGO_ENABLED") == "1"
253
254 ccEnv, ok := os.LookupEnv("CC")
255 if cgoEnabled && !ok {
256 return fmt.Errorf("CC must be set")
257 }
258 os.Setenv("CC", quotePathIfNeeded(abs(ccEnv)))
259
260
261
262 if err := absEnv(cgoEnvVars, cgoAbsEnvFlags); err != nil {
263 return fmt.Errorf("error modifying cgo environment to absolute path: %v", err)
264 }
265
266
267 absCachePath := abs(*cachePath)
268 os.Setenv("GOCACHE", absCachePath)
269 os.Setenv("GOMODCACHE", absCachePath)
270 os.Setenv("GOPATH", absCachePath)
271
272 listArgs := goenv.goCmd("list")
273 if len(build.Default.BuildTags) > 0 {
274 listArgs = append(listArgs, "-tags", strings.Join(build.Default.BuildTags, ","))
275 }
276
277 if cgoEnabled {
278 listArgs = append(listArgs, "-compiled=true")
279 }
280
281 listArgs = append(listArgs, "-json", "builtin", "std", "runtime/cgo")
282
283 jsonFile, err := os.Create(*out)
284 if err != nil {
285 return err
286 }
287 defer jsonFile.Close()
288
289 jsonData := &bytes.Buffer{}
290 if err := goenv.runCommandToFile(jsonData, os.Stderr, listArgs); err != nil {
291 return err
292 }
293
294 encoder := json.NewEncoder(jsonFile)
295 decoder := json.NewDecoder(jsonData)
296 pathReplaceFn := func(s string) string {
297 if strings.HasPrefix(s, absCachePath) {
298 return strings.Replace(s, absCachePath, filepath.Join("__BAZEL_EXECROOT__", *cachePath), 1)
299 }
300
301 return s
302 }
303 for decoder.More() {
304 var pkg *goListPackage
305 if err := decoder.Decode(&pkg); err != nil {
306 return err
307 }
308 if err := encoder.Encode(flatPackageForStd(cloneBase, pkg, pathReplaceFn)); err != nil {
309 return err
310 }
311 }
312
313 return nil
314 }
315
View as plain text