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