Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/go/internal/list

     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  	"fmt"
    14  	"io"
    15  	"os"
    16  	"sort"
    17  	"strings"
    18  	"text/template"
    19  
    20  	"cmd/go/internal/base"
    21  	"cmd/go/internal/cache"
    22  	"cmd/go/internal/cfg"
    23  	"cmd/go/internal/load"
    24  	"cmd/go/internal/modinfo"
    25  	"cmd/go/internal/modload"
    26  	"cmd/go/internal/str"
    27  	"cmd/go/internal/work"
    28  )
    29  
    30  var CmdList = &base.Command{
    31  	// Note: -f -json -m are listed explicitly because they are the most common list flags.
    32  	// Do not send CLs removing them because they're covered by [list flags].
    33  	UsageLine: "go list [-f format] [-json] [-m] [list flags] [build flags] [packages]",
    34  	Short:     "list packages or modules",
    35  	Long: `
    36  List lists the named packages, one per line.
    37  The most commonly-used flags are -f and -json, which control the form
    38  of the output printed for each package. Other list flags, documented below,
    39  control more specific details.
    40  
    41  The default output shows the package import path:
    42  
    43      bytes
    44      encoding/json
    45      github.com/gorilla/mux
    46      golang.org/x/net/html
    47  
    48  The -f flag specifies an alternate format for the list, using the
    49  syntax of package template. The default output is equivalent
    50  to -f '{{.ImportPath}}'. The struct being passed to the template is:
    51  
    52      type Package struct {
    53          Dir           string   // directory containing package sources
    54          ImportPath    string   // import path of package in dir
    55          ImportComment string   // path in import comment on package statement
    56          Name          string   // package name
    57          Doc           string   // package documentation string
    58          Target        string   // install path
    59          Shlib         string   // the shared library that contains this package (only set when -linkshared)
    60          Goroot        bool     // is this package in the Go root?
    61          Standard      bool     // is this package part of the standard Go library?
    62          Stale         bool     // would 'go install' do anything for this package?
    63          StaleReason   string   // explanation for Stale==true
    64          Root          string   // Go root or Go path dir containing this package
    65          ConflictDir   string   // this directory shadows Dir in $GOPATH
    66          BinaryOnly    bool     // binary-only package (no longer supported)
    67          ForTest       string   // package is only for use in named test
    68          Export        string   // file containing export data (when using -export)
    69          BuildID       string   // build ID of the compiled package (when using -export)
    70          Module        *Module  // info about package's containing module, if any (can be nil)
    71          Match         []string // command-line patterns matching this package
    72          DepOnly       bool     // package is only a dependency, not explicitly listed
    73  
    74          // Source files
    75          GoFiles         []string   // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
    76          CgoFiles        []string   // .go source files that import "C"
    77          CompiledGoFiles []string   // .go files presented to compiler (when using -compiled)
    78          IgnoredGoFiles  []string   // .go source files ignored due to build constraints
    79          IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
    80          CFiles          []string   // .c source files
    81          CXXFiles        []string   // .cc, .cxx and .cpp source files
    82          MFiles          []string   // .m source files
    83          HFiles          []string   // .h, .hh, .hpp and .hxx source files
    84          FFiles          []string   // .f, .F, .for and .f90 Fortran source files
    85          SFiles          []string   // .s source files
    86          SwigFiles       []string   // .swig files
    87          SwigCXXFiles    []string   // .swigcxx files
    88          SysoFiles       []string   // .syso object files to add to archive
    89          TestGoFiles     []string   // _test.go files in package
    90          XTestGoFiles    []string   // _test.go files outside package
    91  
    92          // Embedded files
    93          EmbedPatterns      []string // //go:embed patterns
    94          EmbedFiles         []string // files matched by EmbedPatterns
    95          TestEmbedPatterns  []string // //go:embed patterns in TestGoFiles
    96          TestEmbedFiles     []string // files matched by TestEmbedPatterns
    97          XTestEmbedPatterns []string // //go:embed patterns in XTestGoFiles
    98          XTestEmbedFiles    []string // files matched by XTestEmbedPatterns
    99  
   100          // Cgo directives
   101          CgoCFLAGS    []string // cgo: flags for C compiler
   102          CgoCPPFLAGS  []string // cgo: flags for C preprocessor
   103          CgoCXXFLAGS  []string // cgo: flags for C++ compiler
   104          CgoFFLAGS    []string // cgo: flags for Fortran compiler
   105          CgoLDFLAGS   []string // cgo: flags for linker
   106          CgoPkgConfig []string // cgo: pkg-config names
   107  
   108          // Dependency information
   109          Imports      []string          // import paths used by this package
   110          ImportMap    map[string]string // map from source import to ImportPath (identity entries omitted)
   111          Deps         []string          // all (recursively) imported dependencies
   112          TestImports  []string          // imports from TestGoFiles
   113          XTestImports []string          // imports from XTestGoFiles
   114  
   115          // Error information
   116          Incomplete bool            // this package or a dependency has an error
   117          Error      *PackageError   // error loading package
   118          DepsErrors []*PackageError // errors loading dependencies
   119      }
   120  
   121  Packages stored in vendor directories report an ImportPath that includes the
   122  path to the vendor directory (for example, "d/vendor/p" instead of "p"),
   123  so that the ImportPath uniquely identifies a given copy of a package.
   124  The Imports, Deps, TestImports, and XTestImports lists also contain these
   125  expanded import paths. See golang.org/s/go15vendor for more about vendoring.
   126  
   127  The error information, if any, is
   128  
   129      type PackageError struct {
   130          ImportStack   []string // shortest path from package named on command line to this one
   131          Pos           string   // position of error (if present, file:line:col)
   132          Err           string   // the error itself
   133      }
   134  
   135  The module information is a Module struct, defined in the discussion
   136  of list -m below.
   137  
   138  The template function "join" calls strings.Join.
   139  
   140  The template function "context" returns the build context, defined as:
   141  
   142      type Context struct {
   143          GOARCH        string   // target architecture
   144          GOOS          string   // target operating system
   145          GOROOT        string   // Go root
   146          GOPATH        string   // Go path
   147          CgoEnabled    bool     // whether cgo can be used
   148          UseAllFiles   bool     // use files regardless of +build lines, file names
   149          Compiler      string   // compiler to assume when computing target paths
   150          BuildTags     []string // build constraints to match in +build lines
   151          ToolTags      []string // toolchain-specific build constraints
   152          ReleaseTags   []string // releases the current release is compatible with
   153          InstallSuffix string   // suffix to use in the name of the install dir
   154      }
   155  
   156  For more information about the meaning of these fields see the documentation
   157  for the go/build package's Context type.
   158  
   159  The -json flag causes the package data to be printed in JSON format
   160  instead of using the template format.
   161  
   162  The -compiled flag causes list to set CompiledGoFiles to the Go source
   163  files presented to the compiler. Typically this means that it repeats
   164  the files listed in GoFiles and then also adds the Go code generated
   165  by processing CgoFiles and SwigFiles. The Imports list contains the
   166  union of all imports from both GoFiles and CompiledGoFiles.
   167  
   168  The -deps flag causes list to iterate over not just the named packages
   169  but also all their dependencies. It visits them in a depth-first post-order
   170  traversal, so that a package is listed only after all its dependencies.
   171  Packages not explicitly listed on the command line will have the DepOnly
   172  field set to true.
   173  
   174  The -e flag changes the handling of erroneous packages, those that
   175  cannot be found or are malformed. By default, the list command
   176  prints an error to standard error for each erroneous package and
   177  omits the packages from consideration during the usual printing.
   178  With the -e flag, the list command never prints errors to standard
   179  error and instead processes the erroneous packages with the usual
   180  printing. Erroneous packages will have a non-empty ImportPath and
   181  a non-nil Error field; other information may or may not be missing
   182  (zeroed).
   183  
   184  The -export flag causes list to set the Export field to the name of a
   185  file containing up-to-date export information for the given package.
   186  
   187  The -find flag causes list to identify the named packages but not
   188  resolve their dependencies: the Imports and Deps lists will be empty.
   189  
   190  The -test flag causes list to report not only the named packages
   191  but also their test binaries (for packages with tests), to convey to
   192  source code analysis tools exactly how test binaries are constructed.
   193  The reported import path for a test binary is the import path of
   194  the package followed by a ".test" suffix, as in "math/rand.test".
   195  When building a test, it is sometimes necessary to rebuild certain
   196  dependencies specially for that test (most commonly the tested
   197  package itself). The reported import path of a package recompiled
   198  for a particular test binary is followed by a space and the name of
   199  the test binary in brackets, as in "math/rand [math/rand.test]"
   200  or "regexp [sort.test]". The ForTest field is also set to the name
   201  of the package being tested ("math/rand" or "sort" in the previous
   202  examples).
   203  
   204  The Dir, Target, Shlib, Root, ConflictDir, and Export file paths
   205  are all absolute paths.
   206  
   207  By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir
   208  (that is, paths relative to Dir, not absolute paths).
   209  The generated files added when using the -compiled and -test flags
   210  are absolute paths referring to cached copies of generated Go source files.
   211  Although they are Go source files, the paths may not end in ".go".
   212  
   213  The -m flag causes list to list modules instead of packages.
   214  
   215  When listing modules, the -f flag still specifies a format template
   216  applied to a Go struct, but now a Module struct:
   217  
   218      type Module struct {
   219          Path      string       // module path
   220          Version   string       // module version
   221          Versions  []string     // available module versions (with -versions)
   222          Replace   *Module      // replaced by this module
   223          Time      *time.Time   // time version was created
   224          Update    *Module      // available update, if any (with -u)
   225          Main      bool         // is this the main module?
   226          Indirect  bool         // is this module only an indirect dependency of main module?
   227          Dir       string       // directory holding files for this module, if any
   228          GoMod     string       // path to go.mod file used when loading this module, if any
   229          GoVersion string       // go version used in module
   230          Retracted string       // retraction information, if any (with -retracted or -u)
   231          Error     *ModuleError // error loading module
   232      }
   233  
   234      type ModuleError struct {
   235          Err string // the error itself
   236      }
   237  
   238  The file GoMod refers to may be outside the module directory if the
   239  module is in the module cache or if the -modfile flag is used.
   240  
   241  The default output is to print the module path and then
   242  information about the version and replacement if any.
   243  For example, 'go list -m all' might print:
   244  
   245      my/main/module
   246      golang.org/x/text v0.3.0 => /tmp/text
   247      rsc.io/pdf v0.1.1
   248  
   249  The Module struct has a String method that formats this
   250  line of output, so that the default format is equivalent
   251  to -f '{{.String}}'.
   252  
   253  Note that when a module has been replaced, its Replace field
   254  describes the replacement module, and its Dir field is set to
   255  the replacement's source code, if present. (That is, if Replace
   256  is non-nil, then Dir is set to Replace.Dir, with no access to
   257  the replaced source code.)
   258  
   259  The -u flag adds information about available upgrades.
   260  When the latest version of a given module is newer than
   261  the current one, list -u sets the Module's Update field
   262  to information about the newer module. list -u will also set
   263  the module's Retracted field if the current version is retracted.
   264  The Module's String method indicates an available upgrade by
   265  formatting the newer version in brackets after the current version.
   266  If a version is retracted, the string "(retracted)" will follow it.
   267  For example, 'go list -m -u all' might print:
   268  
   269      my/main/module
   270      golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
   271      rsc.io/pdf v0.1.1 (retracted) [v0.1.2]
   272  
   273  (For tools, 'go list -m -u -json all' may be more convenient to parse.)
   274  
   275  The -versions flag causes list to set the Module's Versions field
   276  to a list of all known versions of that module, ordered according
   277  to semantic versioning, earliest to latest. The flag also changes
   278  the default output format to display the module path followed by the
   279  space-separated version list.
   280  
   281  The -retracted flag causes list to report information about retracted
   282  module versions. When -retracted is used with -f or -json, the Retracted
   283  field will be set to a string explaining why the version was retracted.
   284  The string is taken from comments on the retract directive in the
   285  module's go.mod file. When -retracted is used with -versions, retracted
   286  versions are listed together with unretracted versions. The -retracted
   287  flag may be used with or without -m.
   288  
   289  The arguments to list -m are interpreted as a list of modules, not packages.
   290  The main module is the module containing the current directory.
   291  The active modules are the main module and its dependencies.
   292  With no arguments, list -m shows the main module.
   293  With arguments, list -m shows the modules specified by the arguments.
   294  Any of the active modules can be specified by its module path.
   295  The special pattern "all" specifies all the active modules, first the main
   296  module and then dependencies sorted by module path.
   297  A pattern containing "..." specifies the active modules whose
   298  module paths match the pattern.
   299  A query of the form path@version specifies the result of that query,
   300  which is not limited to active modules.
   301  See 'go help modules' for more about module queries.
   302  
   303  The template function "module" takes a single string argument
   304  that must be a module path or query and returns the specified
   305  module as a Module struct. If an error occurs, the result will
   306  be a Module struct with a non-nil Error field.
   307  
   308  For more about build flags, see 'go help build'.
   309  
   310  For more about specifying packages, see 'go help packages'.
   311  
   312  For more about modules, see https://golang.org/ref/mod.
   313  	`,
   314  }
   315  
   316  func init() {
   317  	CmdList.Run = runList // break init cycle
   318  	work.AddBuildFlags(CmdList, work.DefaultBuildFlags)
   319  }
   320  
   321  var (
   322  	listCompiled  = CmdList.Flag.Bool("compiled", false, "")
   323  	listDeps      = CmdList.Flag.Bool("deps", false, "")
   324  	listE         = CmdList.Flag.Bool("e", false, "")
   325  	listExport    = CmdList.Flag.Bool("export", false, "")
   326  	listFmt       = CmdList.Flag.String("f", "", "")
   327  	listFind      = CmdList.Flag.Bool("find", false, "")
   328  	listJson      = CmdList.Flag.Bool("json", false, "")
   329  	listM         = CmdList.Flag.Bool("m", false, "")
   330  	listRetracted = CmdList.Flag.Bool("retracted", false, "")
   331  	listTest      = CmdList.Flag.Bool("test", false, "")
   332  	listU         = CmdList.Flag.Bool("u", false, "")
   333  	listVersions  = CmdList.Flag.Bool("versions", false, "")
   334  )
   335  
   336  var nl = []byte{'\n'}
   337  
   338  func runList(ctx context.Context, cmd *base.Command, args []string) {
   339  	if *listFmt != "" && *listJson == true {
   340  		base.Fatalf("go list -f cannot be used with -json")
   341  	}
   342  
   343  	work.BuildInit()
   344  	out := newTrackingWriter(os.Stdout)
   345  	defer out.w.Flush()
   346  
   347  	if *listFmt == "" {
   348  		if *listM {
   349  			*listFmt = "{{.String}}"
   350  			if *listVersions {
   351  				*listFmt = `{{.Path}}{{range .Versions}} {{.}}{{end}}{{if .Deprecated}} (deprecated){{end}}`
   352  			}
   353  		} else {
   354  			*listFmt = "{{.ImportPath}}"
   355  		}
   356  	}
   357  
   358  	var do func(interface{})
   359  	if *listJson {
   360  		do = func(x interface{}) {
   361  			b, err := json.MarshalIndent(x, "", "\t")
   362  			if err != nil {
   363  				out.Flush()
   364  				base.Fatalf("%s", err)
   365  			}
   366  			out.Write(b)
   367  			out.Write(nl)
   368  		}
   369  	} else {
   370  		var cachedCtxt *Context
   371  		context := func() *Context {
   372  			if cachedCtxt == nil {
   373  				cachedCtxt = newContext(&cfg.BuildContext)
   374  			}
   375  			return cachedCtxt
   376  		}
   377  		fm := template.FuncMap{
   378  			"join":    strings.Join,
   379  			"context": context,
   380  			"module":  func(path string) *modinfo.ModulePublic { return modload.ModuleInfo(ctx, path) },
   381  		}
   382  		tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
   383  		if err != nil {
   384  			base.Fatalf("%s", err)
   385  		}
   386  		do = func(x interface{}) {
   387  			if err := tmpl.Execute(out, x); err != nil {
   388  				out.Flush()
   389  				base.Fatalf("%s", err)
   390  			}
   391  			if out.NeedNL() {
   392  				out.Write(nl)
   393  			}
   394  		}
   395  	}
   396  
   397  	modload.Init()
   398  	if *listRetracted {
   399  		if cfg.BuildMod == "vendor" {
   400  			base.Fatalf("go list -retracted cannot be used when vendoring is enabled")
   401  		}
   402  		if !modload.Enabled() {
   403  			base.Fatalf("go list -retracted can only be used in module-aware mode")
   404  		}
   405  	}
   406  
   407  	if *listM {
   408  		// Module mode.
   409  		if *listCompiled {
   410  			base.Fatalf("go list -compiled cannot be used with -m")
   411  		}
   412  		if *listDeps {
   413  			// TODO(rsc): Could make this mean something with -m.
   414  			base.Fatalf("go list -deps cannot be used with -m")
   415  		}
   416  		if *listExport {
   417  			base.Fatalf("go list -export cannot be used with -m")
   418  		}
   419  		if *listFind {
   420  			base.Fatalf("go list -find cannot be used with -m")
   421  		}
   422  		if *listTest {
   423  			base.Fatalf("go list -test cannot be used with -m")
   424  		}
   425  
   426  		if modload.Init(); !modload.Enabled() {
   427  			base.Fatalf("go list -m: not using modules")
   428  		}
   429  
   430  		modload.LoadModFile(ctx) // Sets cfg.BuildMod as a side-effect.
   431  		if cfg.BuildMod == "vendor" {
   432  			const actionDisabledFormat = "go list -m: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)"
   433  
   434  			if *listVersions {
   435  				base.Fatalf(actionDisabledFormat, "determine available versions")
   436  			}
   437  			if *listU {
   438  				base.Fatalf(actionDisabledFormat, "determine available upgrades")
   439  			}
   440  
   441  			for _, arg := range args {
   442  				// In vendor mode, the module graph is incomplete: it contains only the
   443  				// explicit module dependencies and the modules that supply packages in
   444  				// the import graph. Reject queries that imply more information than that.
   445  				if arg == "all" {
   446  					base.Fatalf(actionDisabledFormat, "compute 'all'")
   447  				}
   448  				if strings.Contains(arg, "...") {
   449  					base.Fatalf(actionDisabledFormat, "match module patterns")
   450  				}
   451  			}
   452  		}
   453  
   454  		var mode modload.ListMode
   455  		if *listU {
   456  			mode |= modload.ListU | modload.ListRetracted | modload.ListDeprecated
   457  		}
   458  		if *listRetracted {
   459  			mode |= modload.ListRetracted
   460  		}
   461  		if *listVersions {
   462  			mode |= modload.ListVersions
   463  			if *listRetracted {
   464  				mode |= modload.ListRetractedVersions
   465  			}
   466  		}
   467  		mods, err := modload.ListModules(ctx, args, mode)
   468  		if !*listE {
   469  			for _, m := range mods {
   470  				if m.Error != nil {
   471  					base.Errorf("go list -m: %v", m.Error.Err)
   472  				}
   473  			}
   474  			if err != nil {
   475  				base.Errorf("go list -m: %v", err)
   476  			}
   477  			base.ExitIfErrors()
   478  		}
   479  		for _, m := range mods {
   480  			do(m)
   481  		}
   482  		return
   483  	}
   484  
   485  	// Package mode (not -m).
   486  	if *listU {
   487  		base.Fatalf("go list -u can only be used with -m")
   488  	}
   489  	if *listVersions {
   490  		base.Fatalf("go list -versions can only be used with -m")
   491  	}
   492  
   493  	// These pairings make no sense.
   494  	if *listFind && *listDeps {
   495  		base.Fatalf("go list -deps cannot be used with -find")
   496  	}
   497  	if *listFind && *listTest {
   498  		base.Fatalf("go list -test cannot be used with -find")
   499  	}
   500  
   501  	pkgOpts := load.PackageOpts{
   502  		IgnoreImports:   *listFind,
   503  		ModResolveTests: *listTest,
   504  	}
   505  	pkgs := load.PackagesAndErrors(ctx, pkgOpts, args)
   506  	if !*listE {
   507  		w := 0
   508  		for _, pkg := range pkgs {
   509  			if pkg.Error != nil {
   510  				base.Errorf("%v", pkg.Error)
   511  				continue
   512  			}
   513  			pkgs[w] = pkg
   514  			w++
   515  		}
   516  		pkgs = pkgs[:w]
   517  		base.ExitIfErrors()
   518  	}
   519  
   520  	if cache.Default() == nil {
   521  		// These flags return file names pointing into the build cache,
   522  		// so the build cache must exist.
   523  		if *listCompiled {
   524  			base.Fatalf("go list -compiled requires build cache")
   525  		}
   526  		if *listExport {
   527  			base.Fatalf("go list -export requires build cache")
   528  		}
   529  		if *listTest {
   530  			base.Fatalf("go list -test requires build cache")
   531  		}
   532  	}
   533  
   534  	if *listTest {
   535  		c := cache.Default()
   536  		// Add test binaries to packages to be listed.
   537  		for _, p := range pkgs {
   538  			if len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 {
   539  				var pmain, ptest, pxtest *load.Package
   540  				var err error
   541  				if *listE {
   542  					pmain, ptest, pxtest = load.TestPackagesAndErrors(ctx, pkgOpts, p, nil)
   543  				} else {
   544  					pmain, ptest, pxtest, err = load.TestPackagesFor(ctx, pkgOpts, p, nil)
   545  					if err != nil {
   546  						base.Errorf("can't load test package: %s", err)
   547  					}
   548  				}
   549  				if pmain != nil {
   550  					pkgs = append(pkgs, pmain)
   551  					data := *pmain.Internal.TestmainGo
   552  					h := cache.NewHash("testmain")
   553  					h.Write([]byte("testmain\n"))
   554  					h.Write(data)
   555  					out, _, err := c.Put(h.Sum(), bytes.NewReader(data))
   556  					if err != nil {
   557  						base.Fatalf("%s", err)
   558  					}
   559  					pmain.GoFiles[0] = c.OutputFile(out)
   560  				}
   561  				if ptest != nil && ptest != p {
   562  					pkgs = append(pkgs, ptest)
   563  				}
   564  				if pxtest != nil {
   565  					pkgs = append(pkgs, pxtest)
   566  				}
   567  			}
   568  		}
   569  	}
   570  
   571  	// Remember which packages are named on the command line.
   572  	cmdline := make(map[*load.Package]bool)
   573  	for _, p := range pkgs {
   574  		cmdline[p] = true
   575  	}
   576  
   577  	if *listDeps {
   578  		// Note: This changes the order of the listed packages
   579  		// from "as written on the command line" to
   580  		// "a depth-first post-order traversal".
   581  		// (The dependency exploration order for a given node
   582  		// is alphabetical, same as listed in .Deps.)
   583  		// Note that -deps is applied after -test,
   584  		// so that you only get descriptions of tests for the things named
   585  		// explicitly on the command line, not for all dependencies.
   586  		pkgs = loadPackageList(pkgs)
   587  	}
   588  
   589  	// Do we need to run a build to gather information?
   590  	needStale := *listJson || strings.Contains(*listFmt, ".Stale")
   591  	if needStale || *listExport || *listCompiled {
   592  		var b work.Builder
   593  		b.Init()
   594  		b.IsCmdList = true
   595  		b.NeedExport = *listExport
   596  		b.NeedCompiledGoFiles = *listCompiled
   597  		a := &work.Action{}
   598  		// TODO: Use pkgsFilter?
   599  		for _, p := range pkgs {
   600  			if len(p.GoFiles)+len(p.CgoFiles) > 0 {
   601  				a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
   602  			}
   603  		}
   604  		b.Do(ctx, a)
   605  	}
   606  
   607  	for _, p := range pkgs {
   608  		// Show vendor-expanded paths in listing
   609  		p.TestImports = p.Resolve(p.TestImports)
   610  		p.XTestImports = p.Resolve(p.XTestImports)
   611  		p.DepOnly = !cmdline[p]
   612  
   613  		if *listCompiled {
   614  			p.Imports = str.StringList(p.Imports, p.Internal.CompiledImports)
   615  		}
   616  	}
   617  
   618  	if *listTest {
   619  		all := pkgs
   620  		if !*listDeps {
   621  			all = loadPackageList(pkgs)
   622  		}
   623  		// Update import paths to distinguish the real package p
   624  		// from p recompiled for q.test.
   625  		// This must happen only once the build code is done
   626  		// looking at import paths, because it will get very confused
   627  		// if it sees these.
   628  		old := make(map[string]string)
   629  		for _, p := range all {
   630  			if p.ForTest != "" {
   631  				new := p.Desc()
   632  				old[new] = p.ImportPath
   633  				p.ImportPath = new
   634  			}
   635  			p.DepOnly = !cmdline[p]
   636  		}
   637  		// Update import path lists to use new strings.
   638  		m := make(map[string]string)
   639  		for _, p := range all {
   640  			for _, p1 := range p.Internal.Imports {
   641  				if p1.ForTest != "" {
   642  					m[old[p1.ImportPath]] = p1.ImportPath
   643  				}
   644  			}
   645  			for i, old := range p.Imports {
   646  				if new := m[old]; new != "" {
   647  					p.Imports[i] = new
   648  				}
   649  			}
   650  			for old := range m {
   651  				delete(m, old)
   652  			}
   653  		}
   654  		// Recompute deps lists using new strings, from the leaves up.
   655  		for _, p := range all {
   656  			deps := make(map[string]bool)
   657  			for _, p1 := range p.Internal.Imports {
   658  				deps[p1.ImportPath] = true
   659  				for _, d := range p1.Deps {
   660  					deps[d] = true
   661  				}
   662  			}
   663  			p.Deps = make([]string, 0, len(deps))
   664  			for d := range deps {
   665  				p.Deps = append(p.Deps, d)
   666  			}
   667  			sort.Strings(p.Deps)
   668  		}
   669  	}
   670  
   671  	// TODO(golang.org/issue/40676): This mechanism could be extended to support
   672  	// -u without -m.
   673  	if *listRetracted {
   674  		// Load retractions for modules that provide packages that will be printed.
   675  		// TODO(golang.org/issue/40775): Packages from the same module refer to
   676  		// distinct ModulePublic instance. It would be nice if they could all point
   677  		// to the same instance. This would require additional global state in
   678  		// modload.loaded, so that should be refactored first. For now, we update
   679  		// all instances.
   680  		modToArg := make(map[*modinfo.ModulePublic]string)
   681  		argToMods := make(map[string][]*modinfo.ModulePublic)
   682  		var args []string
   683  		addModule := func(mod *modinfo.ModulePublic) {
   684  			if mod.Version == "" {
   685  				return
   686  			}
   687  			arg := fmt.Sprintf("%s@%s", mod.Path, mod.Version)
   688  			if argToMods[arg] == nil {
   689  				args = append(args, arg)
   690  			}
   691  			argToMods[arg] = append(argToMods[arg], mod)
   692  			modToArg[mod] = arg
   693  		}
   694  		for _, p := range pkgs {
   695  			if p.Module == nil {
   696  				continue
   697  			}
   698  			addModule(p.Module)
   699  			if p.Module.Replace != nil {
   700  				addModule(p.Module.Replace)
   701  			}
   702  		}
   703  
   704  		if len(args) > 0 {
   705  			var mode modload.ListMode
   706  			if *listRetracted {
   707  				mode |= modload.ListRetracted
   708  			}
   709  			rmods, err := modload.ListModules(ctx, args, mode)
   710  			if err != nil && !*listE {
   711  				base.Errorf("go list -retracted: %v", err)
   712  			}
   713  			for i, arg := range args {
   714  				rmod := rmods[i]
   715  				for _, mod := range argToMods[arg] {
   716  					mod.Retracted = rmod.Retracted
   717  					if rmod.Error != nil && mod.Error == nil {
   718  						mod.Error = rmod.Error
   719  					}
   720  				}
   721  			}
   722  		}
   723  	}
   724  
   725  	// Record non-identity import mappings in p.ImportMap.
   726  	for _, p := range pkgs {
   727  		nRaw := len(p.Internal.RawImports)
   728  		for i, path := range p.Imports {
   729  			var srcPath string
   730  			if i < nRaw {
   731  				srcPath = p.Internal.RawImports[i]
   732  			} else {
   733  				// This path is not within the raw imports, so it must be an import
   734  				// found only within CompiledGoFiles. Those paths are found in
   735  				// CompiledImports.
   736  				srcPath = p.Internal.CompiledImports[i-nRaw]
   737  			}
   738  
   739  			if path != srcPath {
   740  				if p.ImportMap == nil {
   741  					p.ImportMap = make(map[string]string)
   742  				}
   743  				p.ImportMap[srcPath] = path
   744  			}
   745  		}
   746  	}
   747  
   748  	for _, p := range pkgs {
   749  		do(&p.PackagePublic)
   750  	}
   751  }
   752  
   753  // loadPackageList is like load.PackageList, but prints error messages and exits
   754  // with nonzero status if listE is not set and any package in the expanded list
   755  // has errors.
   756  func loadPackageList(roots []*load.Package) []*load.Package {
   757  	pkgs := load.PackageList(roots)
   758  
   759  	if !*listE {
   760  		for _, pkg := range pkgs {
   761  			if pkg.Error != nil {
   762  				base.Errorf("%v", pkg.Error)
   763  			}
   764  		}
   765  	}
   766  
   767  	return pkgs
   768  }
   769  
   770  // TrackingWriter tracks the last byte written on every write so
   771  // we can avoid printing a newline if one was already written or
   772  // if there is no output at all.
   773  type TrackingWriter struct {
   774  	w    *bufio.Writer
   775  	last byte
   776  }
   777  
   778  func newTrackingWriter(w io.Writer) *TrackingWriter {
   779  	return &TrackingWriter{
   780  		w:    bufio.NewWriter(w),
   781  		last: '\n',
   782  	}
   783  }
   784  
   785  func (t *TrackingWriter) Write(p []byte) (n int, err error) {
   786  	n, err = t.w.Write(p)
   787  	if n > 0 {
   788  		t.last = p[n-1]
   789  	}
   790  	return
   791  }
   792  
   793  func (t *TrackingWriter) Flush() {
   794  	t.w.Flush()
   795  }
   796  
   797  func (t *TrackingWriter) NeedNL() bool {
   798  	return t.last != '\n'
   799  }
   800  

View as plain text