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