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

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

View as plain text