Source file src/cmd/go/internal/list/list.go

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

View as plain text