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 will be set to a string explaining why the version was retracted.
   304  The string is 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://golang.org/ref/mod.
   343  	`,
   344  }
   345  
   346  func init() {
   347  	CmdList.Run = runList // break init cycle
   348  	work.AddBuildFlags(CmdList, work.DefaultBuildFlags)
   349  	if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign {
   350  		work.AddCoverFlags(CmdList, nil)
   351  	}
   352  	CmdList.Flag.Var(&listJsonFields, "json", "")
   353  }
   354  
   355  var (
   356  	listCompiled   = CmdList.Flag.Bool("compiled", false, "")
   357  	listDeps       = CmdList.Flag.Bool("deps", false, "")
   358  	listE          = CmdList.Flag.Bool("e", false, "")
   359  	listExport     = CmdList.Flag.Bool("export", false, "")
   360  	listFmt        = CmdList.Flag.String("f", "", "")
   361  	listFind       = CmdList.Flag.Bool("find", false, "")
   362  	listJson       bool
   363  	listJsonFields jsonFlag // If not empty, only output these fields.
   364  	listM          = CmdList.Flag.Bool("m", false, "")
   365  	listRetracted  = CmdList.Flag.Bool("retracted", false, "")
   366  	listReuse      = CmdList.Flag.String("reuse", "", "")
   367  	listTest       = CmdList.Flag.Bool("test", false, "")
   368  	listU          = CmdList.Flag.Bool("u", false, "")
   369  	listVersions   = CmdList.Flag.Bool("versions", false, "")
   370  )
   371  
   372  // A StringsFlag is a command-line flag that interprets its argument
   373  // as a space-separated list of possibly-quoted strings.
   374  type jsonFlag map[string]bool
   375  
   376  func (v *jsonFlag) Set(s string) error {
   377  	if v, err := strconv.ParseBool(s); err == nil {
   378  		listJson = v
   379  		return nil
   380  	}
   381  	listJson = true
   382  	if *v == nil {
   383  		*v = make(map[string]bool)
   384  	}
   385  	for _, f := range strings.Split(s, ",") {
   386  		(*v)[f] = true
   387  	}
   388  	return nil
   389  }
   390  
   391  func (v *jsonFlag) String() string {
   392  	var fields []string
   393  	for f := range *v {
   394  		fields = append(fields, f)
   395  	}
   396  	sort.Strings(fields)
   397  	return strings.Join(fields, ",")
   398  }
   399  
   400  func (v *jsonFlag) IsBoolFlag() bool {
   401  	return true
   402  }
   403  
   404  func (v *jsonFlag) needAll() bool {
   405  	return len(*v) == 0
   406  }
   407  
   408  func (v *jsonFlag) needAny(fields ...string) bool {
   409  	if v.needAll() {
   410  		return true
   411  	}
   412  	for _, f := range fields {
   413  		if (*v)[f] {
   414  			return true
   415  		}
   416  	}
   417  	return false
   418  }
   419  
   420  var nl = []byte{'\n'}
   421  
   422  func runList(ctx context.Context, cmd *base.Command, args []string) {
   423  	modload.InitWorkfile()
   424  
   425  	if *listFmt != "" && listJson {
   426  		base.Fatalf("go list -f cannot be used with -json")
   427  	}
   428  	if *listReuse != "" && !*listM {
   429  		base.Fatalf("go list -reuse cannot be used without -m")
   430  	}
   431  	if *listReuse != "" && modload.HasModRoot() {
   432  		base.Fatalf("go list -reuse cannot be used inside a module")
   433  	}
   434  
   435  	work.BuildInit()
   436  	out := newTrackingWriter(os.Stdout)
   437  	defer out.w.Flush()
   438  
   439  	if *listFmt == "" {
   440  		if *listM {
   441  			*listFmt = "{{.String}}"
   442  			if *listVersions {
   443  				*listFmt = `{{.Path}}{{range .Versions}} {{.}}{{end}}{{if .Deprecated}} (deprecated){{end}}`
   444  			}
   445  		} else {
   446  			*listFmt = "{{.ImportPath}}"
   447  		}
   448  	}
   449  
   450  	var do func(x any)
   451  	if listJson {
   452  		do = func(x any) {
   453  			if !listJsonFields.needAll() {
   454  				//  Set x to a copy of itself with all non-requested fields cleared.
   455  				v := reflect.New(reflect.TypeOf(x).Elem()).Elem() // do is always called with a non-nil pointer.
   456  				v.Set(reflect.ValueOf(x).Elem())
   457  				for i := 0; i < v.NumField(); i++ {
   458  					if !listJsonFields.needAny(v.Type().Field(i).Name) {
   459  						v.Field(i).SetZero()
   460  					}
   461  				}
   462  				x = v.Interface()
   463  			}
   464  			b, err := json.MarshalIndent(x, "", "\t")
   465  			if err != nil {
   466  				out.Flush()
   467  				base.Fatalf("%s", err)
   468  			}
   469  			out.Write(b)
   470  			out.Write(nl)
   471  		}
   472  	} else {
   473  		var cachedCtxt *Context
   474  		context := func() *Context {
   475  			if cachedCtxt == nil {
   476  				cachedCtxt = newContext(&cfg.BuildContext)
   477  			}
   478  			return cachedCtxt
   479  		}
   480  		fm := template.FuncMap{
   481  			"join":    strings.Join,
   482  			"context": context,
   483  			"module":  func(path string) *modinfo.ModulePublic { return modload.ModuleInfo(ctx, path) },
   484  		}
   485  		tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
   486  		if err != nil {
   487  			base.Fatalf("%s", err)
   488  		}
   489  		do = func(x any) {
   490  			if err := tmpl.Execute(out, x); err != nil {
   491  				out.Flush()
   492  				base.Fatalf("%s", err)
   493  			}
   494  			if out.NeedNL() {
   495  				out.Write(nl)
   496  			}
   497  		}
   498  	}
   499  
   500  	modload.Init()
   501  	if *listRetracted {
   502  		if cfg.BuildMod == "vendor" {
   503  			base.Fatalf("go list -retracted cannot be used when vendoring is enabled")
   504  		}
   505  		if !modload.Enabled() {
   506  			base.Fatalf("go list -retracted can only be used in module-aware mode")
   507  		}
   508  	}
   509  
   510  	if *listM {
   511  		// Module mode.
   512  		if *listCompiled {
   513  			base.Fatalf("go list -compiled cannot be used with -m")
   514  		}
   515  		if *listDeps {
   516  			// TODO(rsc): Could make this mean something with -m.
   517  			base.Fatalf("go list -deps cannot be used with -m")
   518  		}
   519  		if *listExport {
   520  			base.Fatalf("go list -export cannot be used with -m")
   521  		}
   522  		if *listFind {
   523  			base.Fatalf("go list -find cannot be used with -m")
   524  		}
   525  		if *listTest {
   526  			base.Fatalf("go list -test cannot be used with -m")
   527  		}
   528  
   529  		if modload.Init(); !modload.Enabled() {
   530  			base.Fatalf("go: list -m cannot be used with GO111MODULE=off")
   531  		}
   532  
   533  		modload.LoadModFile(ctx) // Sets cfg.BuildMod as a side-effect.
   534  		if cfg.BuildMod == "vendor" {
   535  			const actionDisabledFormat = "go: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)"
   536  
   537  			if *listVersions {
   538  				base.Fatalf(actionDisabledFormat, "determine available versions")
   539  			}
   540  			if *listU {
   541  				base.Fatalf(actionDisabledFormat, "determine available upgrades")
   542  			}
   543  
   544  			for _, arg := range args {
   545  				// In vendor mode, the module graph is incomplete: it contains only the
   546  				// explicit module dependencies and the modules that supply packages in
   547  				// the import graph. Reject queries that imply more information than that.
   548  				if arg == "all" {
   549  					base.Fatalf(actionDisabledFormat, "compute 'all'")
   550  				}
   551  				if strings.Contains(arg, "...") {
   552  					base.Fatalf(actionDisabledFormat, "match module patterns")
   553  				}
   554  			}
   555  		}
   556  
   557  		var mode modload.ListMode
   558  		if *listU {
   559  			mode |= modload.ListU | modload.ListRetracted | modload.ListDeprecated
   560  		}
   561  		if *listRetracted {
   562  			mode |= modload.ListRetracted
   563  		}
   564  		if *listVersions {
   565  			mode |= modload.ListVersions
   566  			if *listRetracted {
   567  				mode |= modload.ListRetractedVersions
   568  			}
   569  		}
   570  		if *listReuse != "" && len(args) == 0 {
   571  			base.Fatalf("go: list -m -reuse only has an effect with module@version arguments")
   572  		}
   573  		mods, err := modload.ListModules(ctx, args, mode, *listReuse)
   574  		if !*listE {
   575  			for _, m := range mods {
   576  				if m.Error != nil {
   577  					base.Error(errors.New(m.Error.Err))
   578  				}
   579  			}
   580  			if err != nil {
   581  				base.Error(err)
   582  			}
   583  			base.ExitIfErrors()
   584  		}
   585  		for _, m := range mods {
   586  			do(m)
   587  		}
   588  		return
   589  	}
   590  
   591  	// Package mode (not -m).
   592  	if *listU {
   593  		base.Fatalf("go list -u can only be used with -m")
   594  	}
   595  	if *listVersions {
   596  		base.Fatalf("go list -versions can only be used with -m")
   597  	}
   598  
   599  	// These pairings make no sense.
   600  	if *listFind && *listDeps {
   601  		base.Fatalf("go list -deps cannot be used with -find")
   602  	}
   603  	if *listFind && *listTest {
   604  		base.Fatalf("go list -test cannot be used with -find")
   605  	}
   606  	if *listFind && *listExport {
   607  		base.Fatalf("go list -export cannot be used with -find")
   608  	}
   609  
   610  	pkgOpts := load.PackageOpts{
   611  		IgnoreImports:      *listFind,
   612  		ModResolveTests:    *listTest,
   613  		AutoVCS:            true,
   614  		SuppressBuildInfo:  !*listExport && !listJsonFields.needAny("Stale", "StaleReason"),
   615  		SuppressEmbedFiles: !*listExport && !listJsonFields.needAny("EmbedFiles", "TestEmbedFiles", "XTestEmbedFiles"),
   616  	}
   617  	pkgs := load.PackagesAndErrors(ctx, pkgOpts, args)
   618  	if !*listE {
   619  		w := 0
   620  		for _, pkg := range pkgs {
   621  			if pkg.Error != nil {
   622  				base.Errorf("%v", pkg.Error)
   623  				continue
   624  			}
   625  			pkgs[w] = pkg
   626  			w++
   627  		}
   628  		pkgs = pkgs[:w]
   629  		base.ExitIfErrors()
   630  	}
   631  
   632  	if *listTest {
   633  		c := cache.Default()
   634  		// Add test binaries to packages to be listed.
   635  
   636  		var wg sync.WaitGroup
   637  		sema := semaphore.NewWeighted(int64(runtime.GOMAXPROCS(0)))
   638  		type testPackageSet struct {
   639  			p, pmain, ptest, pxtest *load.Package
   640  		}
   641  		var testPackages []testPackageSet
   642  		for _, p := range pkgs {
   643  			if len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 {
   644  				var pmain, ptest, pxtest *load.Package
   645  				var err error
   646  				if *listE {
   647  					sema.Acquire(ctx, 1)
   648  					wg.Add(1)
   649  					done := func() {
   650  						sema.Release(1)
   651  						wg.Done()
   652  					}
   653  					pmain, ptest, pxtest = load.TestPackagesAndErrors(ctx, done, pkgOpts, p, nil)
   654  				} else {
   655  					pmain, ptest, pxtest, err = load.TestPackagesFor(ctx, pkgOpts, p, nil)
   656  					if err != nil {
   657  						base.Fatalf("go: can't load test package: %s", err)
   658  					}
   659  				}
   660  				testPackages = append(testPackages, testPackageSet{p, pmain, ptest, pxtest})
   661  			}
   662  		}
   663  		wg.Wait()
   664  		for _, pkgset := range testPackages {
   665  			p, pmain, ptest, pxtest := pkgset.p, pkgset.pmain, pkgset.ptest, pkgset.pxtest
   666  			if pmain != nil {
   667  				pkgs = append(pkgs, pmain)
   668  				data := *pmain.Internal.TestmainGo
   669  				sema.Acquire(ctx, 1)
   670  				wg.Add(1)
   671  				go func() {
   672  					h := cache.NewHash("testmain")
   673  					h.Write([]byte("testmain\n"))
   674  					h.Write(data)
   675  					out, _, err := c.Put(h.Sum(), bytes.NewReader(data))
   676  					if err != nil {
   677  						base.Fatalf("%s", err)
   678  					}
   679  					pmain.GoFiles[0] = c.OutputFile(out)
   680  					sema.Release(1)
   681  					wg.Done()
   682  				}()
   683  
   684  			}
   685  			if ptest != nil && ptest != p {
   686  				pkgs = append(pkgs, ptest)
   687  			}
   688  			if pxtest != nil {
   689  				pkgs = append(pkgs, pxtest)
   690  			}
   691  		}
   692  
   693  		wg.Wait()
   694  	}
   695  
   696  	// Remember which packages are named on the command line.
   697  	cmdline := make(map[*load.Package]bool)
   698  	for _, p := range pkgs {
   699  		cmdline[p] = true
   700  	}
   701  
   702  	if *listDeps {
   703  		// Note: This changes the order of the listed packages
   704  		// from "as written on the command line" to
   705  		// "a depth-first post-order traversal".
   706  		// (The dependency exploration order for a given node
   707  		// is alphabetical, same as listed in .Deps.)
   708  		// Note that -deps is applied after -test,
   709  		// so that you only get descriptions of tests for the things named
   710  		// explicitly on the command line, not for all dependencies.
   711  		pkgs = loadPackageList(pkgs)
   712  	}
   713  
   714  	// Do we need to run a build to gather information?
   715  	needStale := (listJson && listJsonFields.needAny("Stale", "StaleReason")) || strings.Contains(*listFmt, ".Stale")
   716  	if needStale || *listExport || *listCompiled {
   717  		b := work.NewBuilder("")
   718  		if *listE {
   719  			b.AllowErrors = true
   720  		}
   721  		defer func() {
   722  			if err := b.Close(); err != nil {
   723  				base.Fatal(err)
   724  			}
   725  		}()
   726  
   727  		b.IsCmdList = true
   728  		b.NeedExport = *listExport
   729  		b.NeedCompiledGoFiles = *listCompiled
   730  		if cfg.Experiment.CoverageRedesign && cfg.BuildCover {
   731  			load.PrepareForCoverageBuild(pkgs)
   732  		}
   733  		a := &work.Action{}
   734  		// TODO: Use pkgsFilter?
   735  		for _, p := range pkgs {
   736  			if len(p.GoFiles)+len(p.CgoFiles) > 0 {
   737  				a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
   738  			}
   739  		}
   740  		b.Do(ctx, a)
   741  	}
   742  
   743  	for _, p := range pkgs {
   744  		// Show vendor-expanded paths in listing
   745  		p.TestImports = p.Resolve(p.TestImports)
   746  		p.XTestImports = p.Resolve(p.XTestImports)
   747  		p.DepOnly = !cmdline[p]
   748  
   749  		if *listCompiled {
   750  			p.Imports = str.StringList(p.Imports, p.Internal.CompiledImports)
   751  		}
   752  	}
   753  
   754  	if *listTest || (cfg.BuildPGO == "auto" && len(cmdline) > 1) {
   755  		all := pkgs
   756  		if !*listDeps {
   757  			all = loadPackageList(pkgs)
   758  		}
   759  		// Update import paths to distinguish the real package p
   760  		// from p recompiled for q.test, or to distinguish between
   761  		// p compiled with different PGO profiles.
   762  		// This must happen only once the build code is done
   763  		// looking at import paths, because it will get very confused
   764  		// if it sees these.
   765  		old := make(map[string]string)
   766  		for _, p := range all {
   767  			if p.ForTest != "" || p.Internal.ForMain != "" {
   768  				new := p.Desc()
   769  				old[new] = p.ImportPath
   770  				p.ImportPath = new
   771  			}
   772  			p.DepOnly = !cmdline[p]
   773  		}
   774  		// Update import path lists to use new strings.
   775  		m := make(map[string]string)
   776  		for _, p := range all {
   777  			for _, p1 := range p.Internal.Imports {
   778  				if p1.ForTest != "" || p1.Internal.ForMain != "" {
   779  					m[old[p1.ImportPath]] = p1.ImportPath
   780  				}
   781  			}
   782  			for i, old := range p.Imports {
   783  				if new := m[old]; new != "" {
   784  					p.Imports[i] = new
   785  				}
   786  			}
   787  			clear(m)
   788  		}
   789  	}
   790  
   791  	if listJsonFields.needAny("Deps", "DepsErrors") {
   792  		all := pkgs
   793  		// Make sure we iterate through packages in a postorder traversal,
   794  		// which load.PackageList guarantees. If *listDeps, then all is
   795  		// already in PackageList order. Otherwise, calling load.PackageList
   796  		// provides the guarantee. In the case of an import cycle, the last package
   797  		// visited in the cycle, importing the first encountered package in the cycle,
   798  		// is visited first. The cycle import error will be bubbled up in the traversal
   799  		// order up to the first package in the cycle, covering all the packages
   800  		// in the cycle.
   801  		if !*listDeps {
   802  			all = load.PackageList(pkgs)
   803  		}
   804  		if listJsonFields.needAny("Deps") {
   805  			for _, p := range all {
   806  				collectDeps(p)
   807  			}
   808  		}
   809  		if listJsonFields.needAny("DepsErrors") {
   810  			for _, p := range all {
   811  				collectDepsErrors(p)
   812  			}
   813  		}
   814  	}
   815  
   816  	// TODO(golang.org/issue/40676): This mechanism could be extended to support
   817  	// -u without -m.
   818  	if *listRetracted {
   819  		// Load retractions for modules that provide packages that will be printed.
   820  		// TODO(golang.org/issue/40775): Packages from the same module refer to
   821  		// distinct ModulePublic instance. It would be nice if they could all point
   822  		// to the same instance. This would require additional global state in
   823  		// modload.loaded, so that should be refactored first. For now, we update
   824  		// all instances.
   825  		modToArg := make(map[*modinfo.ModulePublic]string)
   826  		argToMods := make(map[string][]*modinfo.ModulePublic)
   827  		var args []string
   828  		addModule := func(mod *modinfo.ModulePublic) {
   829  			if mod.Version == "" {
   830  				return
   831  			}
   832  			arg := fmt.Sprintf("%s@%s", mod.Path, mod.Version)
   833  			if argToMods[arg] == nil {
   834  				args = append(args, arg)
   835  			}
   836  			argToMods[arg] = append(argToMods[arg], mod)
   837  			modToArg[mod] = arg
   838  		}
   839  		for _, p := range pkgs {
   840  			if p.Module == nil {
   841  				continue
   842  			}
   843  			addModule(p.Module)
   844  			if p.Module.Replace != nil {
   845  				addModule(p.Module.Replace)
   846  			}
   847  		}
   848  
   849  		if len(args) > 0 {
   850  			var mode modload.ListMode
   851  			if *listRetracted {
   852  				mode |= modload.ListRetracted
   853  			}
   854  			rmods, err := modload.ListModules(ctx, args, mode, *listReuse)
   855  			if err != nil && !*listE {
   856  				base.Error(err)
   857  			}
   858  			for i, arg := range args {
   859  				rmod := rmods[i]
   860  				for _, mod := range argToMods[arg] {
   861  					mod.Retracted = rmod.Retracted
   862  					if rmod.Error != nil && mod.Error == nil {
   863  						mod.Error = rmod.Error
   864  					}
   865  				}
   866  			}
   867  		}
   868  	}
   869  
   870  	// Record non-identity import mappings in p.ImportMap.
   871  	for _, p := range pkgs {
   872  		nRaw := len(p.Internal.RawImports)
   873  		for i, path := range p.Imports {
   874  			var srcPath string
   875  			if i < nRaw {
   876  				srcPath = p.Internal.RawImports[i]
   877  			} else {
   878  				// This path is not within the raw imports, so it must be an import
   879  				// found only within CompiledGoFiles. Those paths are found in
   880  				// CompiledImports.
   881  				srcPath = p.Internal.CompiledImports[i-nRaw]
   882  			}
   883  
   884  			if path != srcPath {
   885  				if p.ImportMap == nil {
   886  					p.ImportMap = make(map[string]string)
   887  				}
   888  				p.ImportMap[srcPath] = path
   889  			}
   890  		}
   891  	}
   892  
   893  	for _, p := range pkgs {
   894  		do(&p.PackagePublic)
   895  	}
   896  }
   897  
   898  // loadPackageList is like load.PackageList, but prints error messages and exits
   899  // with nonzero status if listE is not set and any package in the expanded list
   900  // has errors.
   901  func loadPackageList(roots []*load.Package) []*load.Package {
   902  	pkgs := load.PackageList(roots)
   903  
   904  	if !*listE {
   905  		for _, pkg := range pkgs {
   906  			if pkg.Error != nil {
   907  				base.Errorf("%v", pkg.Error)
   908  			}
   909  		}
   910  	}
   911  
   912  	return pkgs
   913  }
   914  
   915  // collectDeps populates p.Deps by iterating over p.Internal.Imports.
   916  // collectDeps must be called on all of p's Imports before being called on p.
   917  func collectDeps(p *load.Package) {
   918  	deps := make(map[string]bool)
   919  
   920  	for _, p := range p.Internal.Imports {
   921  		deps[p.ImportPath] = true
   922  		for _, q := range p.Deps {
   923  			deps[q] = true
   924  		}
   925  	}
   926  
   927  	p.Deps = make([]string, 0, len(deps))
   928  	for dep := range deps {
   929  		p.Deps = append(p.Deps, dep)
   930  	}
   931  	sort.Strings(p.Deps)
   932  }
   933  
   934  // collectDeps populates p.DepsErrors by iterating over p.Internal.Imports.
   935  // collectDepsErrors must be called on all of p's Imports before being called on p.
   936  func collectDepsErrors(p *load.Package) {
   937  	depsErrors := make(map[*load.PackageError]bool)
   938  
   939  	for _, p := range p.Internal.Imports {
   940  		if p.Error != nil {
   941  			depsErrors[p.Error] = true
   942  		}
   943  		for _, q := range p.DepsErrors {
   944  			depsErrors[q] = true
   945  		}
   946  	}
   947  
   948  	p.DepsErrors = make([]*load.PackageError, 0, len(depsErrors))
   949  	for deperr := range depsErrors {
   950  		p.DepsErrors = append(p.DepsErrors, deperr)
   951  	}
   952  	// Sort packages by the package on the top of the stack, which should be
   953  	// the package the error was produced for. Each package can have at most
   954  	// one error set on it.
   955  	sort.Slice(p.DepsErrors, func(i, j int) bool {
   956  		stki, stkj := p.DepsErrors[i].ImportStack, p.DepsErrors[j].ImportStack
   957  		// Some packages are missing import stacks. To ensure deterministic
   958  		// sort order compare two errors that are missing import stacks by
   959  		// their errors' error texts.
   960  		if len(stki) == 0 {
   961  			if len(stkj) != 0 {
   962  				return true
   963  			}
   964  
   965  			return p.DepsErrors[i].Err.Error() < p.DepsErrors[j].Err.Error()
   966  		} else if len(stkj) == 0 {
   967  			return false
   968  		}
   969  		pathi, pathj := stki[len(stki)-1], stkj[len(stkj)-1]
   970  		return pathi < pathj
   971  	})
   972  }
   973  
   974  // TrackingWriter tracks the last byte written on every write so
   975  // we can avoid printing a newline if one was already written or
   976  // if there is no output at all.
   977  type TrackingWriter struct {
   978  	w    *bufio.Writer
   979  	last byte
   980  }
   981  
   982  func newTrackingWriter(w io.Writer) *TrackingWriter {
   983  	return &TrackingWriter{
   984  		w:    bufio.NewWriter(w),
   985  		last: '\n',
   986  	}
   987  }
   988  
   989  func (t *TrackingWriter) Write(p []byte) (n int, err error) {
   990  	n, err = t.w.Write(p)
   991  	if n > 0 {
   992  		t.last = p[n-1]
   993  	}
   994  	return
   995  }
   996  
   997  func (t *TrackingWriter) Flush() {
   998  	t.w.Flush()
   999  }
  1000  
  1001  func (t *TrackingWriter) NeedNL() bool {
  1002  	return t.last != '\n'
  1003  }
  1004  

View as plain text