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

View as plain text