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  	"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  	modload.InitWorkfile()
   340  
   341  	if *listFmt != "" && *listJson == true {
   342  		base.Fatalf("go list -f cannot be used with -json")
   343  	}
   344  
   345  	work.BuildInit()
   346  	out := newTrackingWriter(os.Stdout)
   347  	defer out.w.Flush()
   348  
   349  	if *listFmt == "" {
   350  		if *listM {
   351  			*listFmt = "{{.String}}"
   352  			if *listVersions {
   353  				*listFmt = `{{.Path}}{{range .Versions}} {{.}}{{end}}{{if .Deprecated}} (deprecated){{end}}`
   354  			}
   355  		} else {
   356  			*listFmt = "{{.ImportPath}}"
   357  		}
   358  	}
   359  
   360  	var do func(any)
   361  	if *listJson {
   362  		do = func(x any) {
   363  			b, err := json.MarshalIndent(x, "", "\t")
   364  			if err != nil {
   365  				out.Flush()
   366  				base.Fatalf("%s", err)
   367  			}
   368  			out.Write(b)
   369  			out.Write(nl)
   370  		}
   371  	} else {
   372  		var cachedCtxt *Context
   373  		context := func() *Context {
   374  			if cachedCtxt == nil {
   375  				cachedCtxt = newContext(&cfg.BuildContext)
   376  			}
   377  			return cachedCtxt
   378  		}
   379  		fm := template.FuncMap{
   380  			"join":    strings.Join,
   381  			"context": context,
   382  			"module":  func(path string) *modinfo.ModulePublic { return modload.ModuleInfo(ctx, path) },
   383  		}
   384  		tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
   385  		if err != nil {
   386  			base.Fatalf("%s", err)
   387  		}
   388  		do = func(x any) {
   389  			if err := tmpl.Execute(out, x); err != nil {
   390  				out.Flush()
   391  				base.Fatalf("%s", err)
   392  			}
   393  			if out.NeedNL() {
   394  				out.Write(nl)
   395  			}
   396  		}
   397  	}
   398  
   399  	modload.Init()
   400  	if *listRetracted {
   401  		if cfg.BuildMod == "vendor" {
   402  			base.Fatalf("go list -retracted cannot be used when vendoring is enabled")
   403  		}
   404  		if !modload.Enabled() {
   405  			base.Fatalf("go list -retracted can only be used in module-aware mode")
   406  		}
   407  	}
   408  
   409  	if *listM {
   410  		// Module mode.
   411  		if *listCompiled {
   412  			base.Fatalf("go list -compiled cannot be used with -m")
   413  		}
   414  		if *listDeps {
   415  			// TODO(rsc): Could make this mean something with -m.
   416  			base.Fatalf("go list -deps cannot be used with -m")
   417  		}
   418  		if *listExport {
   419  			base.Fatalf("go list -export cannot be used with -m")
   420  		}
   421  		if *listFind {
   422  			base.Fatalf("go list -find cannot be used with -m")
   423  		}
   424  		if *listTest {
   425  			base.Fatalf("go list -test cannot be used with -m")
   426  		}
   427  
   428  		if modload.Init(); !modload.Enabled() {
   429  			base.Fatalf("go: list -m cannot be used with GO111MODULE=off")
   430  		}
   431  
   432  		modload.LoadModFile(ctx) // Sets cfg.BuildMod as a side-effect.
   433  		if cfg.BuildMod == "vendor" {
   434  			const actionDisabledFormat = "go: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)"
   435  
   436  			if *listVersions {
   437  				base.Fatalf(actionDisabledFormat, "determine available versions")
   438  			}
   439  			if *listU {
   440  				base.Fatalf(actionDisabledFormat, "determine available upgrades")
   441  			}
   442  
   443  			for _, arg := range args {
   444  				// In vendor mode, the module graph is incomplete: it contains only the
   445  				// explicit module dependencies and the modules that supply packages in
   446  				// the import graph. Reject queries that imply more information than that.
   447  				if arg == "all" {
   448  					base.Fatalf(actionDisabledFormat, "compute 'all'")
   449  				}
   450  				if strings.Contains(arg, "...") {
   451  					base.Fatalf(actionDisabledFormat, "match module patterns")
   452  				}
   453  			}
   454  		}
   455  
   456  		var mode modload.ListMode
   457  		if *listU {
   458  			mode |= modload.ListU | modload.ListRetracted | modload.ListDeprecated
   459  		}
   460  		if *listRetracted {
   461  			mode |= modload.ListRetracted
   462  		}
   463  		if *listVersions {
   464  			mode |= modload.ListVersions
   465  			if *listRetracted {
   466  				mode |= modload.ListRetractedVersions
   467  			}
   468  		}
   469  		mods, err := modload.ListModules(ctx, args, mode)
   470  		if !*listE {
   471  			for _, m := range mods {
   472  				if m.Error != nil {
   473  					base.Errorf("go: %v", m.Error.Err)
   474  				}
   475  			}
   476  			if err != nil {
   477  				base.Errorf("go: %v", err)
   478  			}
   479  			base.ExitIfErrors()
   480  		}
   481  		for _, m := range mods {
   482  			do(m)
   483  		}
   484  		return
   485  	}
   486  
   487  	// Package mode (not -m).
   488  	if *listU {
   489  		base.Fatalf("go list -u can only be used with -m")
   490  	}
   491  	if *listVersions {
   492  		base.Fatalf("go list -versions can only be used with -m")
   493  	}
   494  
   495  	// These pairings make no sense.
   496  	if *listFind && *listDeps {
   497  		base.Fatalf("go list -deps cannot be used with -find")
   498  	}
   499  	if *listFind && *listTest {
   500  		base.Fatalf("go list -test cannot be used with -find")
   501  	}
   502  
   503  	pkgOpts := load.PackageOpts{
   504  		IgnoreImports:   *listFind,
   505  		ModResolveTests: *listTest,
   506  		LoadVCS:         true,
   507  	}
   508  	pkgs := load.PackagesAndErrors(ctx, pkgOpts, args)
   509  	if !*listE {
   510  		w := 0
   511  		for _, pkg := range pkgs {
   512  			if pkg.Error != nil {
   513  				base.Errorf("%v", pkg.Error)
   514  				continue
   515  			}
   516  			pkgs[w] = pkg
   517  			w++
   518  		}
   519  		pkgs = pkgs[:w]
   520  		base.ExitIfErrors()
   521  	}
   522  
   523  	if cache.Default() == nil {
   524  		// These flags return file names pointing into the build cache,
   525  		// so the build cache must exist.
   526  		if *listCompiled {
   527  			base.Fatalf("go list -compiled requires build cache")
   528  		}
   529  		if *listExport {
   530  			base.Fatalf("go list -export requires build cache")
   531  		}
   532  		if *listTest {
   533  			base.Fatalf("go list -test requires build cache")
   534  		}
   535  	}
   536  
   537  	if *listTest {
   538  		c := cache.Default()
   539  		// Add test binaries to packages to be listed.
   540  		for _, p := range pkgs {
   541  			if len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 {
   542  				var pmain, ptest, pxtest *load.Package
   543  				var err error
   544  				if *listE {
   545  					pmain, ptest, pxtest = load.TestPackagesAndErrors(ctx, pkgOpts, p, nil)
   546  				} else {
   547  					pmain, ptest, pxtest, err = load.TestPackagesFor(ctx, pkgOpts, p, nil)
   548  					if err != nil {
   549  						base.Errorf("can't load test package: %s", err)
   550  					}
   551  				}
   552  				if pmain != nil {
   553  					pkgs = append(pkgs, pmain)
   554  					data := *pmain.Internal.TestmainGo
   555  					h := cache.NewHash("testmain")
   556  					h.Write([]byte("testmain\n"))
   557  					h.Write(data)
   558  					out, _, err := c.Put(h.Sum(), bytes.NewReader(data))
   559  					if err != nil {
   560  						base.Fatalf("%s", err)
   561  					}
   562  					pmain.GoFiles[0] = c.OutputFile(out)
   563  				}
   564  				if ptest != nil && ptest != p {
   565  					pkgs = append(pkgs, ptest)
   566  				}
   567  				if pxtest != nil {
   568  					pkgs = append(pkgs, pxtest)
   569  				}
   570  			}
   571  		}
   572  	}
   573  
   574  	// Remember which packages are named on the command line.
   575  	cmdline := make(map[*load.Package]bool)
   576  	for _, p := range pkgs {
   577  		cmdline[p] = true
   578  	}
   579  
   580  	if *listDeps {
   581  		// Note: This changes the order of the listed packages
   582  		// from "as written on the command line" to
   583  		// "a depth-first post-order traversal".
   584  		// (The dependency exploration order for a given node
   585  		// is alphabetical, same as listed in .Deps.)
   586  		// Note that -deps is applied after -test,
   587  		// so that you only get descriptions of tests for the things named
   588  		// explicitly on the command line, not for all dependencies.
   589  		pkgs = loadPackageList(pkgs)
   590  	}
   591  
   592  	// Do we need to run a build to gather information?
   593  	needStale := *listJson || strings.Contains(*listFmt, ".Stale")
   594  	if needStale || *listExport || *listCompiled {
   595  		var b work.Builder
   596  		b.Init()
   597  		b.IsCmdList = true
   598  		b.NeedExport = *listExport
   599  		b.NeedCompiledGoFiles = *listCompiled
   600  		a := &work.Action{}
   601  		// TODO: Use pkgsFilter?
   602  		for _, p := range pkgs {
   603  			if len(p.GoFiles)+len(p.CgoFiles) > 0 {
   604  				a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
   605  			}
   606  		}
   607  		b.Do(ctx, a)
   608  	}
   609  
   610  	for _, p := range pkgs {
   611  		// Show vendor-expanded paths in listing
   612  		p.TestImports = p.Resolve(p.TestImports)
   613  		p.XTestImports = p.Resolve(p.XTestImports)
   614  		p.DepOnly = !cmdline[p]
   615  
   616  		if *listCompiled {
   617  			p.Imports = str.StringList(p.Imports, p.Internal.CompiledImports)
   618  		}
   619  	}
   620  
   621  	if *listTest {
   622  		all := pkgs
   623  		if !*listDeps {
   624  			all = loadPackageList(pkgs)
   625  		}
   626  		// Update import paths to distinguish the real package p
   627  		// from p recompiled for q.test.
   628  		// This must happen only once the build code is done
   629  		// looking at import paths, because it will get very confused
   630  		// if it sees these.
   631  		old := make(map[string]string)
   632  		for _, p := range all {
   633  			if p.ForTest != "" {
   634  				new := p.Desc()
   635  				old[new] = p.ImportPath
   636  				p.ImportPath = new
   637  			}
   638  			p.DepOnly = !cmdline[p]
   639  		}
   640  		// Update import path lists to use new strings.
   641  		m := make(map[string]string)
   642  		for _, p := range all {
   643  			for _, p1 := range p.Internal.Imports {
   644  				if p1.ForTest != "" {
   645  					m[old[p1.ImportPath]] = p1.ImportPath
   646  				}
   647  			}
   648  			for i, old := range p.Imports {
   649  				if new := m[old]; new != "" {
   650  					p.Imports[i] = new
   651  				}
   652  			}
   653  			for old := range m {
   654  				delete(m, old)
   655  			}
   656  		}
   657  		// Recompute deps lists using new strings, from the leaves up.
   658  		for _, p := range all {
   659  			deps := make(map[string]bool)
   660  			for _, p1 := range p.Internal.Imports {
   661  				deps[p1.ImportPath] = true
   662  				for _, d := range p1.Deps {
   663  					deps[d] = true
   664  				}
   665  			}
   666  			p.Deps = make([]string, 0, len(deps))
   667  			for d := range deps {
   668  				p.Deps = append(p.Deps, d)
   669  			}
   670  			sort.Strings(p.Deps)
   671  		}
   672  	}
   673  
   674  	// TODO(golang.org/issue/40676): This mechanism could be extended to support
   675  	// -u without -m.
   676  	if *listRetracted {
   677  		// Load retractions for modules that provide packages that will be printed.
   678  		// TODO(golang.org/issue/40775): Packages from the same module refer to
   679  		// distinct ModulePublic instance. It would be nice if they could all point
   680  		// to the same instance. This would require additional global state in
   681  		// modload.loaded, so that should be refactored first. For now, we update
   682  		// all instances.
   683  		modToArg := make(map[*modinfo.ModulePublic]string)
   684  		argToMods := make(map[string][]*modinfo.ModulePublic)
   685  		var args []string
   686  		addModule := func(mod *modinfo.ModulePublic) {
   687  			if mod.Version == "" {
   688  				return
   689  			}
   690  			arg := fmt.Sprintf("%s@%s", mod.Path, mod.Version)
   691  			if argToMods[arg] == nil {
   692  				args = append(args, arg)
   693  			}
   694  			argToMods[arg] = append(argToMods[arg], mod)
   695  			modToArg[mod] = arg
   696  		}
   697  		for _, p := range pkgs {
   698  			if p.Module == nil {
   699  				continue
   700  			}
   701  			addModule(p.Module)
   702  			if p.Module.Replace != nil {
   703  				addModule(p.Module.Replace)
   704  			}
   705  		}
   706  
   707  		if len(args) > 0 {
   708  			var mode modload.ListMode
   709  			if *listRetracted {
   710  				mode |= modload.ListRetracted
   711  			}
   712  			rmods, err := modload.ListModules(ctx, args, mode)
   713  			if err != nil && !*listE {
   714  				base.Errorf("go: %v", err)
   715  			}
   716  			for i, arg := range args {
   717  				rmod := rmods[i]
   718  				for _, mod := range argToMods[arg] {
   719  					mod.Retracted = rmod.Retracted
   720  					if rmod.Error != nil && mod.Error == nil {
   721  						mod.Error = rmod.Error
   722  					}
   723  				}
   724  			}
   725  		}
   726  	}
   727  
   728  	// Record non-identity import mappings in p.ImportMap.
   729  	for _, p := range pkgs {
   730  		nRaw := len(p.Internal.RawImports)
   731  		for i, path := range p.Imports {
   732  			var srcPath string
   733  			if i < nRaw {
   734  				srcPath = p.Internal.RawImports[i]
   735  			} else {
   736  				// This path is not within the raw imports, so it must be an import
   737  				// found only within CompiledGoFiles. Those paths are found in
   738  				// CompiledImports.
   739  				srcPath = p.Internal.CompiledImports[i-nRaw]
   740  			}
   741  
   742  			if path != srcPath {
   743  				if p.ImportMap == nil {
   744  					p.ImportMap = make(map[string]string)
   745  				}
   746  				p.ImportMap[srcPath] = path
   747  			}
   748  		}
   749  	}
   750  
   751  	for _, p := range pkgs {
   752  		do(&p.PackagePublic)
   753  	}
   754  }
   755  
   756  // loadPackageList is like load.PackageList, but prints error messages and exits
   757  // with nonzero status if listE is not set and any package in the expanded list
   758  // has errors.
   759  func loadPackageList(roots []*load.Package) []*load.Package {
   760  	pkgs := load.PackageList(roots)
   761  
   762  	if !*listE {
   763  		for _, pkg := range pkgs {
   764  			if pkg.Error != nil {
   765  				base.Errorf("%v", pkg.Error)
   766  			}
   767  		}
   768  	}
   769  
   770  	return pkgs
   771  }
   772  
   773  // TrackingWriter tracks the last byte written on every write so
   774  // we can avoid printing a newline if one was already written or
   775  // if there is no output at all.
   776  type TrackingWriter struct {
   777  	w    *bufio.Writer
   778  	last byte
   779  }
   780  
   781  func newTrackingWriter(w io.Writer) *TrackingWriter {
   782  	return &TrackingWriter{
   783  		w:    bufio.NewWriter(w),
   784  		last: '\n',
   785  	}
   786  }
   787  
   788  func (t *TrackingWriter) Write(p []byte) (n int, err error) {
   789  	n, err = t.w.Write(p)
   790  	if n > 0 {
   791  		t.last = p[n-1]
   792  	}
   793  	return
   794  }
   795  
   796  func (t *TrackingWriter) Flush() {
   797  	t.w.Flush()
   798  }
   799  
   800  func (t *TrackingWriter) NeedNL() bool {
   801  	return t.last != '\n'
   802  }
   803  

View as plain text