1
2
3
4
5
6 package list
7
8 import (
9 "bufio"
10 "bytes"
11 "context"
12 "encoding/json"
13 "errors"
14 "fmt"
15 "io"
16 "os"
17 "reflect"
18 "runtime"
19 "sort"
20 "strconv"
21 "strings"
22 "sync"
23 "text/template"
24
25 "cmd/go/internal/base"
26 "cmd/go/internal/cache"
27 "cmd/go/internal/cfg"
28 "cmd/go/internal/load"
29 "cmd/go/internal/modinfo"
30 "cmd/go/internal/modload"
31 "cmd/go/internal/str"
32 "cmd/go/internal/work"
33
34 "golang.org/x/sync/semaphore"
35 )
36
37 var CmdList = &base.Command{
38
39
40 UsageLine: "go list [-f format] [-json] [-m] [list flags] [build flags] [packages]",
41 Short: "list packages or modules",
42 Long: `
43 List lists the named packages, one per line.
44 The most commonly-used flags are -f and -json, which control the form
45 of the output printed for each package. Other list flags, documented below,
46 control more specific details.
47
48 The default output shows the package import path:
49
50 bytes
51 encoding/json
52 github.com/gorilla/mux
53 golang.org/x/net/html
54
55 The -f flag specifies an alternate format for the list, using the
56 syntax of package template. The default output is equivalent
57 to -f '{{.ImportPath}}'. The struct being passed to the template is:
58
59 type Package struct {
60 Dir string // directory containing package sources
61 ImportPath string // import path of package in dir
62 ImportComment string // path in import comment on package statement
63 Name string // package name
64 Doc string // package documentation string
65 Target string // install path
66 Shlib string // the shared library that contains this package (only set when -linkshared)
67 Goroot bool // is this package in the Go root?
68 Standard bool // is this package part of the standard Go library?
69 Stale bool // would 'go install' do anything for this package?
70 StaleReason string // explanation for Stale==true
71 Root string // Go root or Go path dir containing this package
72 ConflictDir string // this directory shadows Dir in $GOPATH
73 BinaryOnly bool // binary-only package (no longer supported)
74 ForTest string // package is only for use in named test
75 Export string // file containing export data (when using -export)
76 BuildID string // build ID of the exported package (when using -export)
77 Module *Module // info about package's containing module, if any (can be nil)
78 Match []string // command-line patterns matching this package
79 DepOnly bool // package is only a dependency, not explicitly listed
80 DefaultGODEBUG string // default GODEBUG setting, for main packages
81
82 // Source files
83 GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
84 CgoFiles []string // .go source files that import "C"
85 CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
86 IgnoredGoFiles []string // .go source files ignored due to build constraints
87 IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
88 CFiles []string // .c source files
89 CXXFiles []string // .cc, .cxx and .cpp source files
90 MFiles []string // .m source files
91 HFiles []string // .h, .hh, .hpp and .hxx source files
92 FFiles []string // .f, .F, .for and .f90 Fortran source files
93 SFiles []string // .s source files
94 SwigFiles []string // .swig files
95 SwigCXXFiles []string // .swigcxx files
96 SysoFiles []string // .syso object files to add to archive
97 TestGoFiles []string // _test.go files in package
98 XTestGoFiles []string // _test.go files outside package
99
100 // Embedded files
101 EmbedPatterns []string // //go:embed patterns
102 EmbedFiles []string // files matched by EmbedPatterns
103 TestEmbedPatterns []string // //go:embed patterns in TestGoFiles
104 TestEmbedFiles []string // files matched by TestEmbedPatterns
105 XTestEmbedPatterns []string // //go:embed patterns in XTestGoFiles
106 XTestEmbedFiles []string // files matched by XTestEmbedPatterns
107
108 // Cgo directives
109 CgoCFLAGS []string // cgo: flags for C compiler
110 CgoCPPFLAGS []string // cgo: flags for C preprocessor
111 CgoCXXFLAGS []string // cgo: flags for C++ compiler
112 CgoFFLAGS []string // cgo: flags for Fortran compiler
113 CgoLDFLAGS []string // cgo: flags for linker
114 CgoPkgConfig []string // cgo: pkg-config names
115
116 // Dependency information
117 Imports []string // import paths used by this package
118 ImportMap map[string]string // map from source import to ImportPath (identity entries omitted)
119 Deps []string // all (recursively) imported dependencies
120 TestImports []string // imports from TestGoFiles
121 XTestImports []string // imports from XTestGoFiles
122
123 // Error information
124 Incomplete bool // this package or a dependency has an error
125 Error *PackageError // error loading package
126 DepsErrors []*PackageError // errors loading dependencies
127 }
128
129 Packages stored in vendor directories report an ImportPath that includes the
130 path to the vendor directory (for example, "d/vendor/p" instead of "p"),
131 so that the ImportPath uniquely identifies a given copy of a package.
132 The Imports, Deps, TestImports, and XTestImports lists also contain these
133 expanded import paths. See golang.org/s/go15vendor for more about vendoring.
134
135 The error information, if any, is
136
137 type PackageError struct {
138 ImportStack []string // shortest path from package named on command line to this one
139 Pos string // position of error (if present, file:line:col)
140 Err string // the error itself
141 }
142
143 The module information is a Module struct, defined in the discussion
144 of list -m below.
145
146 The template function "join" calls strings.Join.
147
148 The template function "json" marshals its arguments to JSON.
149
150 The template function "context" returns the build context, defined as:
151
152 type Context struct {
153 GOARCH string // target architecture
154 GOOS string // target operating system
155 GOROOT string // Go root
156 GOPATH string // Go path
157 CgoEnabled bool // whether cgo can be used
158 UseAllFiles bool // use files regardless of //go:build lines, file names
159 Compiler string // compiler to assume when computing target paths
160 BuildTags []string // build constraints to match in //go:build lines
161 ToolTags []string // toolchain-specific build constraints
162 ReleaseTags []string // releases the current release is compatible with
163 InstallSuffix string // suffix to use in the name of the install dir
164 }
165
166 The template function "module" takes a module path as a parameter,
167 and returns information about the module, defined as the Module struct below.
168
169 For more information about the meaning of these fields see the documentation
170 for the go/build package's Context type.
171
172 The -json flag causes the package data to be printed in JSON format
173 instead of using the template format. The JSON flag can optionally be
174 provided with a set of comma-separated required field names to be output.
175 If so, those required fields will always appear in JSON output, but
176 others may be omitted to save work in computing the JSON struct.
177
178 The -compiled flag causes list to set CompiledGoFiles to the Go source
179 files presented to the compiler. Typically this means that it repeats
180 the files listed in GoFiles and then also adds the Go code generated
181 by processing CgoFiles and SwigFiles. The Imports list contains the
182 union of all imports from both GoFiles and CompiledGoFiles.
183
184 The -deps flag causes list to iterate over not just the named packages
185 but also all their dependencies. It visits them in a depth-first post-order
186 traversal, so that a package is listed only after all its dependencies.
187 Packages not explicitly listed on the command line will have the DepOnly
188 field set to true.
189
190 The -e flag changes the handling of erroneous packages, those that
191 cannot be found or are malformed. By default, the list command
192 prints an error to standard error for each erroneous package and
193 omits the packages from consideration during the usual printing.
194 With the -e flag, the list command never prints errors to standard
195 error and instead processes the erroneous packages with the usual
196 printing. Erroneous packages will have a non-empty ImportPath and
197 a non-nil Error field; other information may or may not be missing
198 (zeroed).
199
200 The -export flag causes list to set the Export field to the name of a
201 file containing up-to-date export data for the given package,
202 and the BuildID field to the build ID of the exported package.
203 The Export file encodes complete type information for the package's
204 public API. To decode it, use the golang.org/x/tools/go/gcexportdata
205 package.
206
207 The -find flag causes list to identify the named packages but not
208 resolve their dependencies: the Imports and Deps lists will be empty.
209 With the -find flag, the -deps, -test and -export commands cannot be
210 used.
211
212 The -test flag causes list to report not only the named packages
213 but also their test binaries (for packages with tests), to convey to
214 source code analysis tools exactly how test binaries are constructed.
215 The reported import path for a test binary is the import path of
216 the package followed by a ".test" suffix, as in "math/rand.test".
217 When building a test, it is sometimes necessary to rebuild certain
218 dependencies specially for that test (most commonly the tested
219 package itself). The reported import path of a package recompiled
220 for a particular test binary is followed by a space and the name of
221 the test binary in brackets, as in "math/rand [math/rand.test]"
222 or "regexp [sort.test]". The ForTest field is also set to the name
223 of the package being tested ("math/rand" or "sort" in the previous
224 examples).
225
226 The Dir, Target, Shlib, Root, ConflictDir, and Export file paths
227 are all absolute paths.
228
229 By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir
230 (that is, paths relative to Dir, not absolute paths).
231 The generated files added when using the -compiled and -test flags
232 are absolute paths referring to cached copies of generated Go source files.
233 Although they are Go source files, the paths may not end in ".go".
234
235 The -m flag causes list to list modules instead of packages.
236
237 When listing modules, the -f flag still specifies a format template
238 applied to a Go struct, but now a Module struct:
239
240 type Module struct {
241 Path string // module path
242 Query string // version query corresponding to this version
243 Version string // module version
244 Versions []string // available module versions
245 Replace *Module // replaced by this module
246 Time *time.Time // time version was created
247 Update *Module // available update (with -u)
248 Main bool // is this the main module?
249 Indirect bool // module is only indirectly needed by main module
250 Dir string // directory holding local copy of files, if any
251 GoMod string // path to go.mod file describing module, if any
252 GoVersion string // go version used in module
253 Retracted []string // retraction information, if any (with -retracted or -u)
254 Deprecated string // deprecation message, if any (with -u)
255 Error *ModuleError // error loading module
256 Sum string // checksum for path, version (as in go.sum)
257 GoModSum string // checksum for go.mod (as in go.sum)
258 Origin any // provenance of module
259 Reuse bool // reuse of old module info is safe
260 }
261
262 type ModuleError struct {
263 Err string // the error itself
264 }
265
266 The file GoMod refers to may be outside the module directory if the
267 module is in the module cache or if the -modfile flag is used.
268
269 The default output is to print the module path and then
270 information about the version and replacement if any.
271 For example, 'go list -m all' might print:
272
273 my/main/module
274 golang.org/x/text v0.3.0 => /tmp/text
275 rsc.io/pdf v0.1.1
276
277 The Module struct has a String method that formats this
278 line of output, so that the default format is equivalent
279 to -f '{{.String}}'.
280
281 Note that when a module has been replaced, its Replace field
282 describes the replacement module, and its Dir field is set to
283 the replacement's source code, if present. (That is, if Replace
284 is non-nil, then Dir is set to Replace.Dir, with no access to
285 the replaced source code.)
286
287 The -u flag adds information about available upgrades.
288 When the latest version of a given module is newer than
289 the current one, list -u sets the Module's Update field
290 to information about the newer module. list -u will also set
291 the module's Retracted field if the current version is retracted.
292 The Module's String method indicates an available upgrade by
293 formatting the newer version in brackets after the current version.
294 If a version is retracted, the string "(retracted)" will follow it.
295 For example, 'go list -m -u all' might print:
296
297 my/main/module
298 golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
299 rsc.io/pdf v0.1.1 (retracted) [v0.1.2]
300
301 (For tools, 'go list -m -u -json all' may be more convenient to parse.)
302
303 The -versions flag causes list to set the Module's Versions field
304 to a list of all known versions of that module, ordered according
305 to semantic versioning, earliest to latest. The flag also changes
306 the default output format to display the module path followed by the
307 space-separated version list.
308
309 The -retracted flag causes list to report information about retracted
310 module versions. When -retracted is used with -f or -json, the Retracted
311 field explains why the version was retracted.
312 The strings are taken from comments on the retract directive in the
313 module's go.mod file. When -retracted is used with -versions, retracted
314 versions are listed together with unretracted versions. The -retracted
315 flag may be used with or without -m.
316
317 The arguments to list -m are interpreted as a list of modules, not packages.
318 The main module is the module containing the current directory.
319 The active modules are the main module and its dependencies.
320 With no arguments, list -m shows the main module.
321 With arguments, list -m shows the modules specified by the arguments.
322 Any of the active modules can be specified by its module path.
323 The special pattern "all" specifies all the active modules, first the main
324 module and then dependencies sorted by module path.
325 A pattern containing "..." specifies the active modules whose
326 module paths match the pattern.
327 A query of the form path@version specifies the result of that query,
328 which is not limited to active modules.
329 See 'go help modules' for more about module queries.
330
331 The template function "module" takes a single string argument
332 that must be a module path or query and returns the specified
333 module as a Module struct. If an error occurs, the result will
334 be a Module struct with a non-nil Error field.
335
336 When using -m, the -reuse=old.json flag accepts the name of file containing
337 the JSON output of a previous 'go list -m -json' invocation with the
338 same set of modifier flags (such as -u, -retracted, and -versions).
339 The go command may use this file to determine that a module is unchanged
340 since the previous invocation and avoid redownloading information about it.
341 Modules that are not redownloaded will be marked in the new output by
342 setting the Reuse field to true. Normally the module cache provides this
343 kind of reuse automatically; the -reuse flag can be useful on systems that
344 do not preserve the module cache.
345
346 For more about build flags, see 'go help build'.
347
348 For more about specifying packages, see 'go help packages'.
349
350 For more about modules, see https://go.dev/ref/mod.
351 `,
352 }
353
354 func init() {
355 CmdList.Run = runList
356
357 work.AddBuildFlags(CmdList, work.OmitJSONFlag)
358 work.AddCoverFlags(CmdList, nil)
359 CmdList.Flag.Var(&listJsonFields, "json", "print the package data in JSON format; optionally specify a comma-separated list of field names to include")
360 }
361
362 var (
363 listCompiled = CmdList.Flag.Bool("compiled", false, "set CompiledGoFiles to the Go source files presented to the compiler")
364 listDeps = CmdList.Flag.Bool("deps", false, "iterate through all dependencies, not just those explicitly listed")
365 listE = CmdList.Flag.Bool("e", false, "change the handling of erroneous packages")
366 listExport = CmdList.Flag.Bool("export", false, "set Export to the file name of the up-to-date export data for the package")
367 listFmt = CmdList.Flag.String("f", "", "specify an alternate `format` for the list, using the syntax of package template")
368 listFind = CmdList.Flag.Bool("find", false, "do not resolve dependencies; print only the matching packages")
369 listJson bool
370 listJsonFields jsonFlag
371 listM = CmdList.Flag.Bool("m", false, "list modules instead of packages")
372 listRetracted = CmdList.Flag.Bool("retracted", false, "show retracted modules")
373 listReuse = CmdList.Flag.String("reuse", "", "reuse output from a previous list run stored in the named `file`")
374 listTest = CmdList.Flag.Bool("test", false, "show not only the named packages but also their test binaries")
375 listU = CmdList.Flag.Bool("u", false, "add information about available upgrades")
376 listVersions = CmdList.Flag.Bool("versions", false, "show the list of all known versions for a module")
377 )
378
379
380
381 type jsonFlag map[string]bool
382
383 func (v *jsonFlag) Set(s string) error {
384 if v, err := strconv.ParseBool(s); err == nil {
385 listJson = v
386 return nil
387 }
388 listJson = true
389 if *v == nil {
390 *v = make(map[string]bool)
391 }
392 for f := range strings.SplitSeq(s, ",") {
393 (*v)[f] = true
394 }
395 return nil
396 }
397
398 func (v *jsonFlag) String() string {
399 fields := make([]string, 0, len(*v))
400 for f := range *v {
401 fields = append(fields, f)
402 }
403 sort.Strings(fields)
404 return strings.Join(fields, ",")
405 }
406
407 func (v *jsonFlag) IsBoolFlag() bool {
408 return true
409 }
410
411 func (v *jsonFlag) needAll() bool {
412 return len(*v) == 0
413 }
414
415 func (v *jsonFlag) needAny(fields ...string) bool {
416 if v.needAll() {
417 return true
418 }
419 for _, f := range fields {
420 if (*v)[f] {
421 return true
422 }
423 }
424 return false
425 }
426
427 var nl = []byte{'\n'}
428
429 func runList(ctx context.Context, cmd *base.Command, args []string) {
430 exp := cfg.Experiment
431
432 for _, arg := range args {
433 if arg == "" {
434 base.Fatalf("go: invalid package: %q", arg)
435 }
436 }
437
438 moduleLoader := modload.NewLoader()
439 moduleLoader.InitWorkfile()
440
441 if *listFmt != "" && listJson {
442 base.Fatalf("go list -f cannot be used with -json")
443 }
444 if *listReuse != "" && !*listM {
445 base.Fatalf("go list -reuse cannot be used without -m")
446 }
447 if *listReuse != "" && moduleLoader.HasModRoot() {
448 base.Fatalf("go list -reuse cannot be used inside a module")
449 }
450
451 work.BuildInit(moduleLoader)
452 out := newTrackingWriter(os.Stdout)
453 defer out.w.Flush()
454
455 if *listFmt == "" {
456 if *listM {
457 *listFmt = "{{.String}}"
458 if *listVersions {
459 *listFmt = `{{.Path}}{{range .Versions}} {{.}}{{end}}{{if .Deprecated}} (deprecated){{end}}`
460 }
461 } else {
462 *listFmt = "{{.ImportPath}}"
463 }
464 }
465
466 var do func(x any)
467 if listJson {
468 do = func(x any) {
469 if !listJsonFields.needAll() {
470
471 v := reflect.New(reflect.TypeOf(x).Elem()).Elem()
472 v.Set(reflect.ValueOf(x).Elem())
473 for i := 0; i < v.NumField(); i++ {
474 if !listJsonFields.needAny(v.Type().Field(i).Name) {
475 v.Field(i).SetZero()
476 }
477 }
478 x = v.Interface()
479 }
480 b, err := json.MarshalIndent(x, "", "\t")
481 if err != nil {
482 out.Flush()
483 base.Fatalf("%s", err)
484 }
485 out.Write(b)
486 out.Write(nl)
487 }
488 } else {
489 var cachedCtxt *Context
490 context := func() *Context {
491 if cachedCtxt == nil {
492 cachedCtxt = newContext(&cfg.BuildContext)
493 }
494 return cachedCtxt
495 }
496 fm := template.FuncMap{
497 "join": strings.Join,
498 "json": func(v any) (string, error) {
499 b, err := json.Marshal(v)
500 return string(b), err
501 },
502 "context": context,
503 "module": func(path string) *modinfo.ModulePublic { return modload.ModuleInfo(moduleLoader, ctx, path) },
504 }
505 tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
506 if err != nil {
507 base.Fatalf("%s", err)
508 }
509 do = func(x any) {
510 if err := tmpl.Execute(out, x); err != nil {
511 out.Flush()
512 base.Fatalf("%s", err)
513 }
514 if out.NeedNL() {
515 out.Write(nl)
516 }
517 }
518 }
519
520 modload.Init(moduleLoader)
521 if *listRetracted {
522 if cfg.BuildMod == "vendor" {
523 base.Fatalf("go list -retracted cannot be used when vendoring is enabled")
524 }
525 if !moduleLoader.Enabled() {
526 base.Fatalf("go list -retracted can only be used in module-aware mode")
527 }
528 }
529
530 if *listM {
531
532 if *listCompiled {
533 base.Fatalf("go list -compiled cannot be used with -m")
534 }
535 if *listDeps {
536
537 base.Fatalf("go list -deps cannot be used with -m")
538 }
539 if *listExport {
540 base.Fatalf("go list -export cannot be used with -m")
541 }
542 if *listFind {
543 base.Fatalf("go list -find cannot be used with -m")
544 }
545 if *listTest {
546 base.Fatalf("go list -test cannot be used with -m")
547 }
548
549 if modload.Init(moduleLoader); !moduleLoader.Enabled() {
550 base.Fatalf("go: list -m cannot be used with GO111MODULE=off")
551 }
552
553 modload.LoadModFile(moduleLoader, ctx)
554 if cfg.BuildMod == "vendor" {
555 const actionDisabledFormat = "go: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)"
556
557 if *listVersions {
558 base.Fatalf(actionDisabledFormat, "determine available versions")
559 }
560 if *listU {
561 base.Fatalf(actionDisabledFormat, "determine available upgrades")
562 }
563
564 for _, arg := range args {
565
566
567
568 if arg == "all" {
569 base.Fatalf(actionDisabledFormat, "compute 'all'")
570 }
571 if strings.Contains(arg, "...") {
572 base.Fatalf(actionDisabledFormat, "match module patterns")
573 }
574 }
575 }
576
577 var mode modload.ListMode
578 if *listU {
579 mode |= modload.ListU | modload.ListRetracted | modload.ListDeprecated
580 }
581 if *listRetracted {
582 mode |= modload.ListRetracted
583 }
584 if *listVersions {
585 mode |= modload.ListVersions
586 if *listRetracted {
587 mode |= modload.ListRetractedVersions
588 }
589 }
590 if *listReuse != "" && len(args) == 0 {
591 base.Fatalf("go: list -m -reuse only has an effect with module@version arguments")
592 }
593 mods, err := modload.ListModules(moduleLoader, ctx, args, mode, *listReuse)
594 if !*listE {
595 for _, m := range mods {
596 if m.Error != nil {
597 base.Error(errors.New(m.Error.Err))
598 }
599 }
600 if err != nil {
601 base.Error(err)
602 }
603 base.ExitIfErrors()
604 }
605 for _, m := range mods {
606 do(m)
607 }
608 return
609 }
610
611
612 if *listU {
613 base.Fatalf("go list -u can only be used with -m")
614 }
615 if *listVersions {
616 base.Fatalf("go list -versions can only be used with -m")
617 }
618
619
620 if *listFind && *listDeps {
621 base.Fatalf("go list -deps cannot be used with -find")
622 }
623 if *listFind && *listTest {
624 base.Fatalf("go list -test cannot be used with -find")
625 }
626 if *listFind && *listExport {
627 base.Fatalf("go list -export cannot be used with -find")
628 }
629
630 pkgOpts := load.PackageOpts{
631 IgnoreImports: *listFind,
632 ModResolveTests: *listTest,
633 AutoVCS: true,
634 SuppressBuildInfo: !*listExport && !listJsonFields.needAny("Stale", "StaleReason"),
635 SuppressEmbedFiles: !*listExport && !listJsonFields.needAny("EmbedFiles", "TestEmbedFiles", "XTestEmbedFiles"),
636 }
637 pkgs := load.PackagesAndErrors(moduleLoader, ctx, pkgOpts, args)
638 if !*listE {
639 w := 0
640 for _, pkg := range pkgs {
641 if pkg.Error != nil {
642 base.Errorf("%v", pkg.Error)
643 continue
644 }
645 pkgs[w] = pkg
646 w++
647 }
648 pkgs = pkgs[:w]
649 base.ExitIfErrors()
650 }
651
652 if *listTest {
653 c := cache.Default()
654
655
656 var wg sync.WaitGroup
657 sema := semaphore.NewWeighted(int64(runtime.GOMAXPROCS(0)))
658 type testPackageSet struct {
659 p, pmain, ptest, pxtest *load.Package
660 }
661 var testPackages []testPackageSet
662 for _, p := range pkgs {
663 if len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 {
664 var pmain, ptest, pxtest *load.Package
665 if *listE {
666 sema.Acquire(ctx, 1)
667 wg.Add(1)
668 done := func() {
669 sema.Release(1)
670 wg.Done()
671 }
672 pmain, ptest, pxtest = load.TestPackagesAndErrors(moduleLoader, ctx, done, pkgOpts, p, nil)
673 } else {
674 var perr *load.Package
675 pmain, ptest, pxtest, perr = load.TestPackagesFor(moduleLoader, ctx, pkgOpts, p, nil)
676 if perr != nil {
677 base.Fatalf("go: can't load test package: %s", perr.Error)
678 }
679 }
680 testPackages = append(testPackages, testPackageSet{p, pmain, ptest, pxtest})
681 }
682 }
683 wg.Wait()
684 for _, pkgset := range testPackages {
685 p, pmain, ptest, pxtest := pkgset.p, pkgset.pmain, pkgset.ptest, pkgset.pxtest
686 if pmain != nil {
687 pkgs = append(pkgs, pmain)
688 data := *pmain.Internal.TestmainGo
689 sema.Acquire(ctx, 1)
690 wg.Add(1)
691 go func() {
692 h := cache.NewHash("testmain")
693 h.Write([]byte("testmain\n"))
694 h.Write(data)
695 out, _, err := c.Put(h.Sum(), bytes.NewReader(data))
696 if err != nil {
697 base.Fatalf("%s", err)
698 }
699 pmain.GoFiles[0] = c.OutputFile(out)
700 sema.Release(1)
701 wg.Done()
702 }()
703
704 }
705 if ptest != nil && ptest != p {
706 pkgs = append(pkgs, ptest)
707 }
708 if pxtest != nil {
709 pkgs = append(pkgs, pxtest)
710 }
711 }
712
713 wg.Wait()
714 }
715
716
717 cmdline := make(map[*load.Package]bool)
718 for _, p := range pkgs {
719 cmdline[p] = true
720 }
721
722 if *listDeps {
723
724
725
726
727
728
729
730
731 pkgs = loadPackageList(pkgs)
732 }
733
734
735 exportNewFormat := exp.GoListExportNewFormat && os.Getenv("TESTGO_EXPORT_ARCHIVE") != "1"
736
737
738 needStale := (listJson && listJsonFields.needAny("Stale", "StaleReason")) || strings.Contains(*listFmt, ".Stale")
739 var buildPkgs []*load.Package
740 if needStale || (*listExport && !exportNewFormat) || (*listCompiled && cfg.BuildCover) {
741 buildPkgs = pkgs
742 } else if *listCompiled {
743
744
745 for _, p := range pkgs {
746 if p.UsesCgo() || p.UsesSwig() {
747
748 buildPkgs = append(buildPkgs, p)
749 continue
750 }
751 p.CompiledGoFiles = str.StringList(p.GoFiles)
752 }
753 }
754 if len(buildPkgs) > 0 {
755 b := work.NewBuilder("", moduleLoader.VendorDirOrEmpty)
756 if *listE {
757 b.AllowErrors = true
758 }
759 defer func() {
760 if err := b.Close(); err != nil {
761 base.Fatal(err)
762 }
763 }()
764
765 b.IsCmdList = true
766 b.NeedExport = *listExport && !exportNewFormat
767 b.NeedCompiledGoFiles = *listCompiled
768 if cfg.BuildCover {
769 load.PrepareForCoverageBuild(moduleLoader, pkgs)
770 }
771 a := &work.Action{}
772
773 for _, p := range buildPkgs {
774 if len(p.GoFiles)+len(p.CgoFiles) > 0 {
775 a.Deps = append(a.Deps, b.AutoAction(moduleLoader, work.ModeInstall, work.ModeInstall, p))
776 }
777 }
778 b.Do(ctx, a)
779 }
780
781
782
783 if *listExport && exportNewFormat {
784 b := work.NewBuilder("", moduleLoader.VendorDirOrEmpty)
785 defer func() {
786 if err := b.Close(); err != nil {
787 base.Fatal(err)
788 }
789 }()
790
791
792
793 b.IsCmdList = true
794 a := &work.Action{}
795
796 for _, p := range pkgs {
797 if len(p.GoFiles)+len(p.CgoFiles) > 0 {
798 a.Deps = append(a.Deps, b.ExportAction(p))
799 }
800 }
801 b.Do(ctx, a)
802 }
803
804 for _, p := range pkgs {
805
806 p.TestImports = p.Resolve(moduleLoader, p.TestImports)
807 p.XTestImports = p.Resolve(moduleLoader, p.XTestImports)
808 p.DepOnly = !cmdline[p]
809
810 if *listCompiled {
811 p.Imports = str.StringList(p.Imports, p.Internal.CompiledImports)
812 }
813 }
814
815 if *listTest || (cfg.BuildPGO == "auto" && len(cmdline) > 1) {
816 all := pkgs
817 if !*listDeps {
818 all = loadPackageList(pkgs)
819 }
820
821
822
823
824
825
826 old := make(map[string]string)
827 for _, p := range all {
828 if p.ForTest != "" || p.Internal.ForMain != "" {
829 new := p.Desc()
830 old[new] = p.ImportPath
831 p.ImportPath = new
832 }
833 p.DepOnly = !cmdline[p]
834 }
835
836 m := make(map[string]string)
837 for _, p := range all {
838 for _, p1 := range p.Internal.Imports {
839 if p1.ForTest != "" || p1.Internal.ForMain != "" {
840 m[old[p1.ImportPath]] = p1.ImportPath
841 }
842 }
843 for i, old := range p.Imports {
844 if new := m[old]; new != "" {
845 p.Imports[i] = new
846 }
847 }
848 clear(m)
849 }
850 }
851
852 if listJsonFields.needAny("Deps", "DepsErrors") {
853 all := pkgs
854
855
856
857
858
859
860
861
862 if !*listDeps {
863 all = load.PackageList(pkgs)
864 }
865 if listJsonFields.needAny("Deps") {
866 for _, p := range all {
867 collectDeps(p)
868 }
869 }
870 if listJsonFields.needAny("DepsErrors") {
871 for _, p := range all {
872 collectDepsErrors(p)
873 }
874 }
875 }
876
877
878
879 if *listRetracted {
880
881
882
883
884
885
886 modToArg := make(map[*modinfo.ModulePublic]string)
887 argToMods := make(map[string][]*modinfo.ModulePublic)
888 var args []string
889 addModule := func(mod *modinfo.ModulePublic) {
890 if mod.Version == "" {
891 return
892 }
893 arg := fmt.Sprintf("%s@%s", mod.Path, mod.Version)
894 if argToMods[arg] == nil {
895 args = append(args, arg)
896 }
897 argToMods[arg] = append(argToMods[arg], mod)
898 modToArg[mod] = arg
899 }
900 for _, p := range pkgs {
901 if p.Module == nil {
902 continue
903 }
904 addModule(p.Module)
905 if p.Module.Replace != nil {
906 addModule(p.Module.Replace)
907 }
908 }
909
910 if len(args) > 0 {
911 var mode modload.ListMode
912 if *listRetracted {
913 mode |= modload.ListRetracted
914 }
915 rmods, err := modload.ListModules(moduleLoader, ctx, args, mode, *listReuse)
916 if err != nil && !*listE {
917 base.Error(err)
918 }
919 for i, arg := range args {
920 rmod := rmods[i]
921 for _, mod := range argToMods[arg] {
922 mod.Retracted = rmod.Retracted
923 if rmod.Error != nil && mod.Error == nil {
924 mod.Error = rmod.Error
925 }
926 }
927 }
928 }
929 }
930
931
932 for _, p := range pkgs {
933 nRaw := len(p.Internal.RawImports)
934 for i, path := range p.Imports {
935 var srcPath string
936 if i < nRaw {
937 srcPath = p.Internal.RawImports[i]
938 } else {
939
940
941
942 srcPath = p.Internal.CompiledImports[i-nRaw]
943 }
944
945 if path != srcPath {
946 if p.ImportMap == nil {
947 p.ImportMap = make(map[string]string)
948 }
949 p.ImportMap[srcPath] = path
950 }
951 }
952 }
953
954 for _, p := range pkgs {
955 do(&p.PackagePublic)
956 }
957 }
958
959
960
961
962 func loadPackageList(roots []*load.Package) []*load.Package {
963 pkgs := load.PackageList(roots)
964
965 if !*listE {
966 for _, pkg := range pkgs {
967 if pkg.Error != nil {
968 base.Errorf("%v", pkg.Error)
969 }
970 }
971 }
972
973 return pkgs
974 }
975
976
977
978 func collectDeps(p *load.Package) {
979 deps := make(map[string]bool)
980
981 for _, p := range p.Internal.Imports {
982 deps[p.ImportPath] = true
983 for _, q := range p.Deps {
984 deps[q] = true
985 }
986 }
987
988 p.Deps = make([]string, 0, len(deps))
989 for dep := range deps {
990 p.Deps = append(p.Deps, dep)
991 }
992 sort.Strings(p.Deps)
993 }
994
995
996
997 func collectDepsErrors(p *load.Package) {
998 depsErrors := make(map[*load.PackageError]bool)
999
1000 for _, p := range p.Internal.Imports {
1001 if p.Error != nil {
1002 depsErrors[p.Error] = true
1003 }
1004 for _, q := range p.DepsErrors {
1005 depsErrors[q] = true
1006 }
1007 }
1008
1009 p.DepsErrors = make([]*load.PackageError, 0, len(depsErrors))
1010 for deperr := range depsErrors {
1011 p.DepsErrors = append(p.DepsErrors, deperr)
1012 }
1013
1014
1015
1016 sort.Slice(p.DepsErrors, func(i, j int) bool {
1017 stki, stkj := p.DepsErrors[i].ImportStack, p.DepsErrors[j].ImportStack
1018
1019
1020
1021 if len(stki) == 0 {
1022 if len(stkj) != 0 {
1023 return true
1024 }
1025
1026 return p.DepsErrors[i].Err.Error() < p.DepsErrors[j].Err.Error()
1027 } else if len(stkj) == 0 {
1028 return false
1029 }
1030 pathi, pathj := stki[len(stki)-1], stkj[len(stkj)-1]
1031 return pathi.Pkg < pathj.Pkg
1032 })
1033 }
1034
1035
1036
1037
1038 type TrackingWriter struct {
1039 w *bufio.Writer
1040 last byte
1041 }
1042
1043 func newTrackingWriter(w io.Writer) *TrackingWriter {
1044 return &TrackingWriter{
1045 w: bufio.NewWriter(w),
1046 last: '\n',
1047 }
1048 }
1049
1050 func (t *TrackingWriter) Write(p []byte) (n int, err error) {
1051 n, err = t.w.Write(p)
1052 if n > 0 {
1053 t.last = p[n-1]
1054 }
1055 return
1056 }
1057
1058 func (t *TrackingWriter) Flush() {
1059 t.w.Flush()
1060 }
1061
1062 func (t *TrackingWriter) NeedNL() bool {
1063 return t.last != '\n'
1064 }
1065
View as plain text