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

View as plain text