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

View as plain text