github.com/bir3/gocompiler@v0.3.205/src/cmd/gocmd/internal/list/list.go (about)

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