Source file src/cmd/go/internal/modget/get.go

     1  // Copyright 2018 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 modget implements the module-aware ``go get'' command.
     6  package modget
     7  
     8  // The arguments to 'go get' are patterns with optional version queries, with
     9  // the version queries defaulting to "upgrade".
    10  //
    11  // The patterns are normally interpreted as package patterns. However, if a
    12  // pattern cannot match a package, it is instead interpreted as a *module*
    13  // pattern. For version queries such as "upgrade" and "patch" that depend on the
    14  // selected version of a module (or of the module containing a package),
    15  // whether a pattern denotes a package or module may change as updates are
    16  // applied (see the example in mod_get_patchmod.txt).
    17  //
    18  // There are a few other ambiguous cases to resolve, too. A package can exist in
    19  // two different modules at the same version: for example, the package
    20  // example.com/foo might be found in module example.com and also in module
    21  // example.com/foo, and those modules may have independent v0.1.0 tags — so the
    22  // input 'example.com/foo@v0.1.0' could syntactically refer to the variant of
    23  // the package loaded from either module! (See mod_get_ambiguous_pkg.txt.)
    24  // If the argument is ambiguous, the user can often disambiguate by specifying
    25  // explicit versions for *all* of the potential module paths involved.
    26  
    27  import (
    28  	"context"
    29  	"errors"
    30  	"fmt"
    31  	"os"
    32  	"path/filepath"
    33  	"runtime"
    34  	"sort"
    35  	"strings"
    36  	"sync"
    37  
    38  	"cmd/go/internal/base"
    39  	"cmd/go/internal/imports"
    40  	"cmd/go/internal/modfetch"
    41  	"cmd/go/internal/modload"
    42  	"cmd/go/internal/par"
    43  	"cmd/go/internal/search"
    44  	"cmd/go/internal/work"
    45  
    46  	"golang.org/x/mod/modfile"
    47  	"golang.org/x/mod/module"
    48  	"golang.org/x/mod/semver"
    49  )
    50  
    51  var CmdGet = &base.Command{
    52  	// Note: flags below are listed explicitly because they're the most common.
    53  	// Do not send CLs removing them because they're covered by [get flags].
    54  	UsageLine: "go get [-t] [-u] [-v] [build flags] [packages]",
    55  	Short:     "add dependencies to current module and install them",
    56  	Long: `
    57  Get resolves its command-line arguments to packages at specific module versions,
    58  updates go.mod to require those versions, and downloads source code into the
    59  module cache.
    60  
    61  To add a dependency for a package or upgrade it to its latest version:
    62  
    63  	go get example.com/pkg
    64  
    65  To upgrade or downgrade a package to a specific version:
    66  
    67  	go get example.com/pkg@v1.2.3
    68  
    69  To remove a dependency on a module and downgrade modules that require it:
    70  
    71  	go get example.com/mod@none
    72  
    73  See https://golang.org/ref/mod#go-get for details.
    74  
    75  In earlier versions of Go, 'go get' was used to build and install packages.
    76  Now, 'go get' is dedicated to adjusting dependencies in go.mod. 'go install'
    77  may be used to build and install commands instead. When a version is specified,
    78  'go install' runs in module-aware mode and ignores the go.mod file in the
    79  current directory. For example:
    80  
    81  	go install example.com/pkg@v1.2.3
    82  	go install example.com/pkg@latest
    83  
    84  See 'go help install' or https://golang.org/ref/mod#go-install for details.
    85  
    86  'go get' accepts the following flags.
    87  
    88  The -t flag instructs get to consider modules needed to build tests of
    89  packages specified on the command line.
    90  
    91  The -u flag instructs get to update modules providing dependencies
    92  of packages named on the command line to use newer minor or patch
    93  releases when available.
    94  
    95  The -u=patch flag (not -u patch) also instructs get to update dependencies,
    96  but changes the default to select patch releases.
    97  
    98  When the -t and -u flags are used together, get will update
    99  test dependencies as well.
   100  
   101  The -x flag prints commands as they are executed. This is useful for
   102  debugging version control commands when a module is downloaded directly
   103  from a repository.
   104  
   105  For more about modules, see https://golang.org/ref/mod.
   106  
   107  For more about specifying packages, see 'go help packages'.
   108  
   109  This text describes the behavior of get using modules to manage source
   110  code and dependencies. If instead the go command is running in GOPATH
   111  mode, the details of get's flags and effects change, as does 'go help get'.
   112  See 'go help gopath-get'.
   113  
   114  See also: go build, go install, go clean, go mod.
   115  	`,
   116  }
   117  
   118  // Note that this help text is a stopgap to make the module-aware get help text
   119  // available even in non-module settings. It should be deleted when the old get
   120  // is deleted. It should NOT be considered to set a precedent of having hierarchical
   121  // help names with dashes.
   122  var HelpModuleGet = &base.Command{
   123  	UsageLine: "module-get",
   124  	Short:     "module-aware go get",
   125  	Long: `
   126  The 'go get' command changes behavior depending on whether the
   127  go command is running in module-aware mode or legacy GOPATH mode.
   128  This help text, accessible as 'go help module-get' even in legacy GOPATH mode,
   129  describes 'go get' as it operates in module-aware mode.
   130  
   131  Usage: ` + CmdGet.UsageLine + `
   132  ` + CmdGet.Long,
   133  }
   134  
   135  var HelpVCS = &base.Command{
   136  	UsageLine: "vcs",
   137  	Short:     "controlling version control with GOVCS",
   138  	Long: `
   139  The 'go get' command can run version control commands like git
   140  to download imported code. This functionality is critical to the decentralized
   141  Go package ecosystem, in which code can be imported from any server,
   142  but it is also a potential security problem, if a malicious server finds a
   143  way to cause the invoked version control command to run unintended code.
   144  
   145  To balance the functionality and security concerns, the 'go get' command
   146  by default will only use git and hg to download code from public servers.
   147  But it will use any known version control system (bzr, fossil, git, hg, svn)
   148  to download code from private servers, defined as those hosting packages
   149  matching the GOPRIVATE variable (see 'go help private'). The rationale behind
   150  allowing only Git and Mercurial is that these two systems have had the most
   151  attention to issues of being run as clients of untrusted servers. In contrast,
   152  Bazaar, Fossil, and Subversion have primarily been used in trusted,
   153  authenticated environments and are not as well scrutinized as attack surfaces.
   154  
   155  The version control command restrictions only apply when using direct version
   156  control access to download code. When downloading modules from a proxy,
   157  'go get' uses the proxy protocol instead, which is always permitted.
   158  By default, the 'go get' command uses the Go module mirror (proxy.golang.org)
   159  for public packages and only falls back to version control for private
   160  packages or when the mirror refuses to serve a public package (typically for
   161  legal reasons). Therefore, clients can still access public code served from
   162  Bazaar, Fossil, or Subversion repositories by default, because those downloads
   163  use the Go module mirror, which takes on the security risk of running the
   164  version control commands using a custom sandbox.
   165  
   166  The GOVCS variable can be used to change the allowed version control systems
   167  for specific packages (identified by a module or import path).
   168  The GOVCS variable applies when building package in both module-aware mode
   169  and GOPATH mode. When using modules, the patterns match against the module path.
   170  When using GOPATH, the patterns match against the import path corresponding to
   171  the root of the version control repository.
   172  
   173  The general form of the GOVCS setting is a comma-separated list of
   174  pattern:vcslist rules. The pattern is a glob pattern that must match
   175  one or more leading elements of the module or import path. The vcslist
   176  is a pipe-separated list of allowed version control commands, or "all"
   177  to allow use of any known command, or "off" to disallow all commands.
   178  Note that if a module matches a pattern with vcslist "off", it may still be
   179  downloaded if the origin server uses the "mod" scheme, which instructs the
   180  go command to download the module using the GOPROXY protocol.
   181  The earliest matching pattern in the list applies, even if later patterns
   182  might also match.
   183  
   184  For example, consider:
   185  
   186  	GOVCS=github.com:git,evil.com:off,*:git|hg
   187  
   188  With this setting, code with a module or import path beginning with
   189  github.com/ can only use git; paths on evil.com cannot use any version
   190  control command, and all other paths (* matches everything) can use
   191  only git or hg.
   192  
   193  The special patterns "public" and "private" match public and private
   194  module or import paths. A path is private if it matches the GOPRIVATE
   195  variable; otherwise it is public.
   196  
   197  If no rules in the GOVCS variable match a particular module or import path,
   198  the 'go get' command applies its default rule, which can now be summarized
   199  in GOVCS notation as 'public:git|hg,private:all'.
   200  
   201  To allow unfettered use of any version control system for any package, use:
   202  
   203  	GOVCS=*:all
   204  
   205  To disable all use of version control, use:
   206  
   207  	GOVCS=*:off
   208  
   209  The 'go env -w' command (see 'go help env') can be used to set the GOVCS
   210  variable for future go command invocations.
   211  `,
   212  }
   213  
   214  var (
   215  	getD        = CmdGet.Flag.Bool("d", true, "")
   216  	getF        = CmdGet.Flag.Bool("f", false, "")
   217  	getFix      = CmdGet.Flag.Bool("fix", false, "")
   218  	getM        = CmdGet.Flag.Bool("m", false, "")
   219  	getT        = CmdGet.Flag.Bool("t", false, "")
   220  	getU        upgradeFlag
   221  	getInsecure = CmdGet.Flag.Bool("insecure", false, "")
   222  	// -v is cfg.BuildV
   223  )
   224  
   225  // upgradeFlag is a custom flag.Value for -u.
   226  type upgradeFlag struct {
   227  	rawVersion string
   228  	version    string
   229  }
   230  
   231  func (*upgradeFlag) IsBoolFlag() bool { return true } // allow -u
   232  
   233  func (v *upgradeFlag) Set(s string) error {
   234  	if s == "false" {
   235  		v.version = ""
   236  		v.rawVersion = ""
   237  	} else if s == "true" {
   238  		v.version = "upgrade"
   239  		v.rawVersion = ""
   240  	} else {
   241  		v.version = s
   242  		v.rawVersion = s
   243  	}
   244  	return nil
   245  }
   246  
   247  func (v *upgradeFlag) String() string { return "" }
   248  
   249  func init() {
   250  	work.AddBuildFlags(CmdGet, work.OmitModFlag)
   251  	CmdGet.Run = runGet // break init loop
   252  	CmdGet.Flag.Var(&getU, "u", "")
   253  }
   254  
   255  func runGet(ctx context.Context, cmd *base.Command, args []string) {
   256  	switch getU.version {
   257  	case "", "upgrade", "patch":
   258  		// ok
   259  	default:
   260  		base.Fatalf("go: unknown upgrade flag -u=%s", getU.rawVersion)
   261  	}
   262  	// TODO(#43684): in the future (Go 1.20), warn that -d is a no-op.
   263  	if !*getD {
   264  		base.Fatalf("go: -d flag may not be disabled")
   265  	}
   266  	if *getF {
   267  		fmt.Fprintf(os.Stderr, "go: -f flag is a no-op when using modules\n")
   268  	}
   269  	if *getFix {
   270  		fmt.Fprintf(os.Stderr, "go: -fix flag is a no-op when using modules\n")
   271  	}
   272  	if *getM {
   273  		base.Fatalf("go: -m flag is no longer supported")
   274  	}
   275  	if *getInsecure {
   276  		base.Fatalf("go: -insecure flag is no longer supported; use GOINSECURE instead")
   277  	}
   278  
   279  	modload.ForceUseModules = true
   280  
   281  	// Do not allow any updating of go.mod until we've applied
   282  	// all the requested changes and checked that the result matches
   283  	// what was requested.
   284  	modload.ExplicitWriteGoMod = true
   285  
   286  	// Allow looking up modules for import paths when outside of a module.
   287  	// 'go get' is expected to do this, unlike other commands.
   288  	modload.AllowMissingModuleImports()
   289  
   290  	// 'go get' no longer builds or installs packages, so there's nothing to do
   291  	// if there's no go.mod file.
   292  	// TODO(#40775): make modload.Init return ErrNoModRoot instead of exiting.
   293  	// We could handle that here by printing a different message.
   294  	modload.Init()
   295  	if !modload.HasModRoot() {
   296  		base.Fatalf("go: go.mod file not found in current directory or any parent directory.\n" +
   297  			"\t'go get' is no longer supported outside a module.\n" +
   298  			"\tTo build and install a command, use 'go install' with a version,\n" +
   299  			"\tlike 'go install example.com/cmd@latest'\n" +
   300  			"\tFor more information, see https://golang.org/doc/go-get-install-deprecation\n" +
   301  			"\tor run 'go help get' or 'go help install'.")
   302  	}
   303  
   304  	queries := parseArgs(ctx, args)
   305  
   306  	r := newResolver(ctx, queries)
   307  	r.performLocalQueries(ctx)
   308  	r.performPathQueries(ctx)
   309  
   310  	for {
   311  		r.performWildcardQueries(ctx)
   312  		r.performPatternAllQueries(ctx)
   313  
   314  		if changed := r.resolveQueries(ctx, queries); changed {
   315  			// 'go get' arguments can be (and often are) package patterns rather than
   316  			// (just) modules. A package can be provided by any module with a prefix
   317  			// of its import path, and a wildcard can even match packages in modules
   318  			// with totally different paths. Because of these effects, and because any
   319  			// change to the selected version of a module can bring in entirely new
   320  			// module paths as dependencies, we need to reissue queries whenever we
   321  			// change the build list.
   322  			//
   323  			// The result of any version query for a given module — even "upgrade" or
   324  			// "patch" — is always relative to the build list at the start of
   325  			// the 'go get' command, not an intermediate state, and is therefore
   326  			// dederministic and therefore cachable, and the constraints on the
   327  			// selected version of each module can only narrow as we iterate.
   328  			//
   329  			// "all" is functionally very similar to a wildcard pattern. The set of
   330  			// packages imported by the main module does not change, and the query
   331  			// result for the module containing each such package also does not change
   332  			// (it is always relative to the initial build list, before applying
   333  			// queries). So the only way that the result of an "all" query can change
   334  			// is if some matching package moves from one module in the build list
   335  			// to another, which should not happen very often.
   336  			continue
   337  		}
   338  
   339  		// When we load imports, we detect the following conditions:
   340  		//
   341  		// - missing transitive depencies that need to be resolved from outside the
   342  		//   current build list (note that these may add new matches for existing
   343  		//   pattern queries!)
   344  		//
   345  		// - transitive dependencies that didn't match any other query,
   346  		//   but need to be upgraded due to the -u flag
   347  		//
   348  		// - ambiguous import errors.
   349  		//   TODO(#27899): Try to resolve ambiguous import errors automatically.
   350  		upgrades := r.findAndUpgradeImports(ctx, queries)
   351  		if changed := r.applyUpgrades(ctx, upgrades); changed {
   352  			continue
   353  		}
   354  
   355  		r.findMissingWildcards(ctx)
   356  		if changed := r.resolveQueries(ctx, r.wildcardQueries); changed {
   357  			continue
   358  		}
   359  
   360  		break
   361  	}
   362  
   363  	r.checkWildcardVersions(ctx)
   364  
   365  	var pkgPatterns []string
   366  	for _, q := range queries {
   367  		if q.matchesPackages {
   368  			pkgPatterns = append(pkgPatterns, q.pattern)
   369  		}
   370  	}
   371  	r.checkPackageProblems(ctx, pkgPatterns)
   372  
   373  	// Everything succeeded. Update go.mod.
   374  	oldReqs := reqsFromGoMod(modload.ModFile())
   375  
   376  	if err := modload.WriteGoMod(ctx); err != nil {
   377  		base.Fatalf("go: %v", err)
   378  	}
   379  
   380  	newReqs := reqsFromGoMod(modload.ModFile())
   381  	r.reportChanges(oldReqs, newReqs)
   382  }
   383  
   384  // parseArgs parses command-line arguments and reports errors.
   385  //
   386  // The command-line arguments are of the form path@version or simply path, with
   387  // implicit @upgrade. path@none is "downgrade away".
   388  func parseArgs(ctx context.Context, rawArgs []string) []*query {
   389  	defer base.ExitIfErrors()
   390  
   391  	var queries []*query
   392  	for _, arg := range search.CleanPatterns(rawArgs) {
   393  		q, err := newQuery(arg)
   394  		if err != nil {
   395  			base.Errorf("go: %v", err)
   396  			continue
   397  		}
   398  
   399  		// If there were no arguments, CleanPatterns returns ".". Set the raw
   400  		// string back to "" for better errors.
   401  		if len(rawArgs) == 0 {
   402  			q.raw = ""
   403  		}
   404  
   405  		// Guard against 'go get x.go', a common mistake.
   406  		// Note that package and module paths may end with '.go', so only print an error
   407  		// if the argument has no version and either has no slash or refers to an existing file.
   408  		if strings.HasSuffix(q.raw, ".go") && q.rawVersion == "" {
   409  			if !strings.Contains(q.raw, "/") {
   410  				base.Errorf("go: %s: arguments must be package or module paths", q.raw)
   411  				continue
   412  			}
   413  			if fi, err := os.Stat(q.raw); err == nil && !fi.IsDir() {
   414  				base.Errorf("go: %s exists as a file, but 'go get' requires package arguments", q.raw)
   415  				continue
   416  			}
   417  		}
   418  
   419  		queries = append(queries, q)
   420  	}
   421  
   422  	return queries
   423  }
   424  
   425  type resolver struct {
   426  	localQueries      []*query // queries for absolute or relative paths
   427  	pathQueries       []*query // package path literal queries in original order
   428  	wildcardQueries   []*query // path wildcard queries in original order
   429  	patternAllQueries []*query // queries with the pattern "all"
   430  
   431  	// Indexed "none" queries. These are also included in the slices above;
   432  	// they are indexed here to speed up noneForPath.
   433  	nonesByPath   map[string]*query // path-literal "@none" queries indexed by path
   434  	wildcardNones []*query          // wildcard "@none" queries
   435  
   436  	// resolvedVersion maps each module path to the version of that module that
   437  	// must be selected in the final build list, along with the first query
   438  	// that resolved the module to that version (the “reason”).
   439  	resolvedVersion map[string]versionReason
   440  
   441  	buildList        []module.Version
   442  	buildListVersion map[string]string // index of buildList (module path → version)
   443  
   444  	initialVersion map[string]string // index of the initial build list at the start of 'go get'
   445  
   446  	missing []pathSet // candidates for missing transitive dependencies
   447  
   448  	work *par.Queue
   449  
   450  	matchInModuleCache par.Cache
   451  }
   452  
   453  type versionReason struct {
   454  	version string
   455  	reason  *query
   456  }
   457  
   458  func newResolver(ctx context.Context, queries []*query) *resolver {
   459  	// LoadModGraph also sets modload.Target, which is needed by various resolver
   460  	// methods.
   461  	const defaultGoVersion = ""
   462  	mg := modload.LoadModGraph(ctx, defaultGoVersion)
   463  
   464  	buildList := mg.BuildList()
   465  	initialVersion := make(map[string]string, len(buildList))
   466  	for _, m := range buildList {
   467  		initialVersion[m.Path] = m.Version
   468  	}
   469  
   470  	r := &resolver{
   471  		work:             par.NewQueue(runtime.GOMAXPROCS(0)),
   472  		resolvedVersion:  map[string]versionReason{},
   473  		buildList:        buildList,
   474  		buildListVersion: initialVersion,
   475  		initialVersion:   initialVersion,
   476  		nonesByPath:      map[string]*query{},
   477  	}
   478  
   479  	for _, q := range queries {
   480  		if q.pattern == "all" {
   481  			r.patternAllQueries = append(r.patternAllQueries, q)
   482  		} else if q.patternIsLocal {
   483  			r.localQueries = append(r.localQueries, q)
   484  		} else if q.isWildcard() {
   485  			r.wildcardQueries = append(r.wildcardQueries, q)
   486  		} else {
   487  			r.pathQueries = append(r.pathQueries, q)
   488  		}
   489  
   490  		if q.version == "none" {
   491  			// Index "none" queries to make noneForPath more efficient.
   492  			if q.isWildcard() {
   493  				r.wildcardNones = append(r.wildcardNones, q)
   494  			} else {
   495  				// All "<path>@none" queries for the same path are identical; we only
   496  				// need to index one copy.
   497  				r.nonesByPath[q.pattern] = q
   498  			}
   499  		}
   500  	}
   501  
   502  	return r
   503  }
   504  
   505  // initialSelected returns the version of the module with the given path that
   506  // was selected at the start of this 'go get' invocation.
   507  func (r *resolver) initialSelected(mPath string) (version string) {
   508  	v, ok := r.initialVersion[mPath]
   509  	if !ok {
   510  		return "none"
   511  	}
   512  	return v
   513  }
   514  
   515  // selected returns the version of the module with the given path that is
   516  // selected in the resolver's current build list.
   517  func (r *resolver) selected(mPath string) (version string) {
   518  	v, ok := r.buildListVersion[mPath]
   519  	if !ok {
   520  		return "none"
   521  	}
   522  	return v
   523  }
   524  
   525  // noneForPath returns a "none" query matching the given module path,
   526  // or found == false if no such query exists.
   527  func (r *resolver) noneForPath(mPath string) (nq *query, found bool) {
   528  	if nq = r.nonesByPath[mPath]; nq != nil {
   529  		return nq, true
   530  	}
   531  	for _, nq := range r.wildcardNones {
   532  		if nq.matchesPath(mPath) {
   533  			return nq, true
   534  		}
   535  	}
   536  	return nil, false
   537  }
   538  
   539  // queryModule wraps modload.Query, substituting r.checkAllowedOr to decide
   540  // allowed versions.
   541  func (r *resolver) queryModule(ctx context.Context, mPath, query string, selected func(string) string) (module.Version, error) {
   542  	current := r.initialSelected(mPath)
   543  	rev, err := modload.Query(ctx, mPath, query, current, r.checkAllowedOr(query, selected))
   544  	if err != nil {
   545  		return module.Version{}, err
   546  	}
   547  	return module.Version{Path: mPath, Version: rev.Version}, nil
   548  }
   549  
   550  // queryPackage wraps modload.QueryPackage, substituting r.checkAllowedOr to
   551  // decide allowed versions.
   552  func (r *resolver) queryPackages(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, err error) {
   553  	results, err := modload.QueryPackages(ctx, pattern, query, selected, r.checkAllowedOr(query, selected))
   554  	if len(results) > 0 {
   555  		pkgMods = make([]module.Version, 0, len(results))
   556  		for _, qr := range results {
   557  			pkgMods = append(pkgMods, qr.Mod)
   558  		}
   559  	}
   560  	return pkgMods, err
   561  }
   562  
   563  // queryPattern wraps modload.QueryPattern, substituting r.checkAllowedOr to
   564  // decide allowed versions.
   565  func (r *resolver) queryPattern(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, mod module.Version, err error) {
   566  	results, modOnly, err := modload.QueryPattern(ctx, pattern, query, selected, r.checkAllowedOr(query, selected))
   567  	if len(results) > 0 {
   568  		pkgMods = make([]module.Version, 0, len(results))
   569  		for _, qr := range results {
   570  			pkgMods = append(pkgMods, qr.Mod)
   571  		}
   572  	}
   573  	if modOnly != nil {
   574  		mod = modOnly.Mod
   575  	}
   576  	return pkgMods, mod, err
   577  }
   578  
   579  // checkAllowedOr is like modload.CheckAllowed, but it always allows the requested
   580  // and current versions (even if they are retracted or otherwise excluded).
   581  func (r *resolver) checkAllowedOr(requested string, selected func(string) string) modload.AllowedFunc {
   582  	return func(ctx context.Context, m module.Version) error {
   583  		if m.Version == requested {
   584  			return modload.CheckExclusions(ctx, m)
   585  		}
   586  		if (requested == "upgrade" || requested == "patch") && m.Version == selected(m.Path) {
   587  			return nil
   588  		}
   589  		return modload.CheckAllowed(ctx, m)
   590  	}
   591  }
   592  
   593  // matchInModule is a caching wrapper around modload.MatchInModule.
   594  func (r *resolver) matchInModule(ctx context.Context, pattern string, m module.Version) (packages []string, err error) {
   595  	type key struct {
   596  		pattern string
   597  		m       module.Version
   598  	}
   599  	type entry struct {
   600  		packages []string
   601  		err      error
   602  	}
   603  
   604  	e := r.matchInModuleCache.Do(key{pattern, m}, func() any {
   605  		match := modload.MatchInModule(ctx, pattern, m, imports.AnyTags())
   606  		if len(match.Errs) > 0 {
   607  			return entry{match.Pkgs, match.Errs[0]}
   608  		}
   609  		return entry{match.Pkgs, nil}
   610  	}).(entry)
   611  
   612  	return e.packages, e.err
   613  }
   614  
   615  // queryNone adds a candidate set to q for each module matching q.pattern.
   616  // Each candidate set has only one possible module version: the matched
   617  // module at version "none".
   618  //
   619  // We interpret arguments to 'go get' as packages first, and fall back to
   620  // modules second. However, no module exists at version "none", and therefore no
   621  // package exists at that version either: we know that the argument cannot match
   622  // any packages, and thus it must match modules instead.
   623  func (r *resolver) queryNone(ctx context.Context, q *query) {
   624  	if search.IsMetaPackage(q.pattern) {
   625  		panic(fmt.Sprintf("internal error: queryNone called with pattern %q", q.pattern))
   626  	}
   627  
   628  	if !q.isWildcard() {
   629  		q.pathOnce(q.pattern, func() pathSet {
   630  			hasModRoot := modload.HasModRoot()
   631  			if hasModRoot && modload.MainModules.Contains(q.pattern) {
   632  				v := module.Version{Path: q.pattern}
   633  				// The user has explicitly requested to downgrade their own module to
   634  				// version "none". This is not an entirely unreasonable request: it
   635  				// could plausibly mean “downgrade away everything that depends on any
   636  				// explicit version of the main module”, or “downgrade away the
   637  				// package with the same path as the main module, found in a module
   638  				// with a prefix of the main module's path”.
   639  				//
   640  				// However, neither of those behaviors would be consistent with the
   641  				// plain meaning of the query. To try to reduce confusion, reject the
   642  				// query explicitly.
   643  				return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{v}, Pattern: q.pattern, Query: q.version})
   644  			}
   645  
   646  			return pathSet{mod: module.Version{Path: q.pattern, Version: "none"}}
   647  		})
   648  	}
   649  
   650  	for _, curM := range r.buildList {
   651  		if !q.matchesPath(curM.Path) {
   652  			continue
   653  		}
   654  		q.pathOnce(curM.Path, func() pathSet {
   655  			if modload.HasModRoot() && curM.Version == "" && modload.MainModules.Contains(curM.Path) {
   656  				return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{curM}, Pattern: q.pattern, Query: q.version})
   657  			}
   658  			return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}}
   659  		})
   660  	}
   661  }
   662  
   663  func (r *resolver) performLocalQueries(ctx context.Context) {
   664  	for _, q := range r.localQueries {
   665  		q.pathOnce(q.pattern, func() pathSet {
   666  			absDetail := ""
   667  			if !filepath.IsAbs(q.pattern) {
   668  				if absPath, err := filepath.Abs(q.pattern); err == nil {
   669  					absDetail = fmt.Sprintf(" (%s)", absPath)
   670  				}
   671  			}
   672  
   673  			// Absolute paths like C:\foo and relative paths like ../foo... are
   674  			// restricted to matching packages in the main module.
   675  			pkgPattern, mainModule := modload.MainModules.DirImportPath(ctx, q.pattern)
   676  			if pkgPattern == "." {
   677  				modload.MustHaveModRoot()
   678  				var modRoots []string
   679  				for _, m := range modload.MainModules.Versions() {
   680  					modRoots = append(modRoots, modload.MainModules.ModRoot(m))
   681  				}
   682  				var plural string
   683  				if len(modRoots) != 1 {
   684  					plural = "s"
   685  				}
   686  				return errSet(fmt.Errorf("%s%s is not within module%s rooted at %s", q.pattern, absDetail, plural, strings.Join(modRoots, ", ")))
   687  			}
   688  
   689  			match := modload.MatchInModule(ctx, pkgPattern, mainModule, imports.AnyTags())
   690  			if len(match.Errs) > 0 {
   691  				return pathSet{err: match.Errs[0]}
   692  			}
   693  
   694  			if len(match.Pkgs) == 0 {
   695  				if q.raw == "" || q.raw == "." {
   696  					return errSet(fmt.Errorf("no package to get in current directory"))
   697  				}
   698  				if !q.isWildcard() {
   699  					modload.MustHaveModRoot()
   700  					return errSet(fmt.Errorf("%s%s is not a package in module rooted at %s", q.pattern, absDetail, modload.MainModules.ModRoot(mainModule)))
   701  				}
   702  				search.WarnUnmatched([]*search.Match{match})
   703  				return pathSet{}
   704  			}
   705  
   706  			return pathSet{pkgMods: []module.Version{mainModule}}
   707  		})
   708  	}
   709  }
   710  
   711  // performWildcardQueries populates the candidates for each query whose pattern
   712  // is a wildcard.
   713  //
   714  // The candidates for a given module path matching (or containing a package
   715  // matching) a wildcard query depend only on the initial build list, but the set
   716  // of modules may be expanded by other queries, so wildcard queries need to be
   717  // re-evaluated whenever a potentially-matching module path is added to the
   718  // build list.
   719  func (r *resolver) performWildcardQueries(ctx context.Context) {
   720  	for _, q := range r.wildcardQueries {
   721  		q := q
   722  		r.work.Add(func() {
   723  			if q.version == "none" {
   724  				r.queryNone(ctx, q)
   725  			} else {
   726  				r.queryWildcard(ctx, q)
   727  			}
   728  		})
   729  	}
   730  	<-r.work.Idle()
   731  }
   732  
   733  // queryWildcard adds a candidate set to q for each module for which:
   734  // 	- some version of the module is already in the build list, and
   735  // 	- that module exists at some version matching q.version, and
   736  // 	- either the module path itself matches q.pattern, or some package within
   737  // 	  the module at q.version matches q.pattern.
   738  func (r *resolver) queryWildcard(ctx context.Context, q *query) {
   739  	// For wildcard patterns, modload.QueryPattern only identifies modules
   740  	// matching the prefix of the path before the wildcard. However, the build
   741  	// list may already contain other modules with matching packages, and we
   742  	// should consider those modules to satisfy the query too.
   743  	// We want to match any packages in existing dependencies, but we only want to
   744  	// resolve new dependencies if nothing else turns up.
   745  	for _, curM := range r.buildList {
   746  		if !q.canMatchInModule(curM.Path) {
   747  			continue
   748  		}
   749  		q.pathOnce(curM.Path, func() pathSet {
   750  			if _, hit := r.noneForPath(curM.Path); hit {
   751  				// This module is being removed, so it will no longer be in the build list
   752  				// (and thus will no longer match the pattern).
   753  				return pathSet{}
   754  			}
   755  
   756  			if modload.MainModules.Contains(curM.Path) && !versionOkForMainModule(q.version) {
   757  				if q.matchesPath(curM.Path) {
   758  					return errSet(&modload.QueryMatchesMainModulesError{
   759  						MainModules: []module.Version{curM},
   760  						Pattern:     q.pattern,
   761  						Query:       q.version,
   762  					})
   763  				}
   764  
   765  				packages, err := r.matchInModule(ctx, q.pattern, curM)
   766  				if err != nil {
   767  					return errSet(err)
   768  				}
   769  				if len(packages) > 0 {
   770  					return errSet(&modload.QueryMatchesPackagesInMainModuleError{
   771  						Pattern:  q.pattern,
   772  						Query:    q.version,
   773  						Packages: packages,
   774  					})
   775  				}
   776  
   777  				return r.tryWildcard(ctx, q, curM)
   778  			}
   779  
   780  			m, err := r.queryModule(ctx, curM.Path, q.version, r.initialSelected)
   781  			if err != nil {
   782  				if !isNoSuchModuleVersion(err) {
   783  					// We can't tell whether a matching version exists.
   784  					return errSet(err)
   785  				}
   786  				// There is no version of curM.Path matching the query.
   787  
   788  				// We haven't checked whether curM contains any matching packages at its
   789  				// currently-selected version, or whether curM.Path itself matches q. If
   790  				// either of those conditions holds, *and* no other query changes the
   791  				// selected version of curM, then we will fail in checkWildcardVersions.
   792  				// (This could be an error, but it's too soon to tell.)
   793  				//
   794  				// However, even then the transitive requirements of some other query
   795  				// may downgrade this module out of the build list entirely, in which
   796  				// case the pattern will no longer include it and it won't be an error.
   797  				//
   798  				// Either way, punt on the query rather than erroring out just yet.
   799  				return pathSet{}
   800  			}
   801  
   802  			return r.tryWildcard(ctx, q, m)
   803  		})
   804  	}
   805  
   806  	// Even if no modules matched, we shouldn't query for a new module to provide
   807  	// the pattern yet: some other query may yet induce a new requirement that
   808  	// will match the wildcard. Instead, we'll check in findMissingWildcards.
   809  }
   810  
   811  // tryWildcard returns a pathSet for module m matching query q.
   812  // If m does not actually match q, tryWildcard returns an empty pathSet.
   813  func (r *resolver) tryWildcard(ctx context.Context, q *query, m module.Version) pathSet {
   814  	mMatches := q.matchesPath(m.Path)
   815  	packages, err := r.matchInModule(ctx, q.pattern, m)
   816  	if err != nil {
   817  		return errSet(err)
   818  	}
   819  	if len(packages) > 0 {
   820  		return pathSet{pkgMods: []module.Version{m}}
   821  	}
   822  	if mMatches {
   823  		return pathSet{mod: m}
   824  	}
   825  	return pathSet{}
   826  }
   827  
   828  // findMissingWildcards adds a candidate set for each query in r.wildcardQueries
   829  // that has not yet resolved to any version containing packages.
   830  func (r *resolver) findMissingWildcards(ctx context.Context) {
   831  	for _, q := range r.wildcardQueries {
   832  		if q.version == "none" || q.matchesPackages {
   833  			continue // q is not “missing”
   834  		}
   835  		r.work.Add(func() {
   836  			q.pathOnce(q.pattern, func() pathSet {
   837  				pkgMods, mod, err := r.queryPattern(ctx, q.pattern, q.version, r.initialSelected)
   838  				if err != nil {
   839  					if isNoSuchPackageVersion(err) && len(q.resolved) > 0 {
   840  						// q already resolved one or more modules but matches no packages.
   841  						// That's ok: this pattern is just a module pattern, and we don't
   842  						// need to add any more modules to satisfy it.
   843  						return pathSet{}
   844  					}
   845  					return errSet(err)
   846  				}
   847  
   848  				return pathSet{pkgMods: pkgMods, mod: mod}
   849  			})
   850  		})
   851  	}
   852  	<-r.work.Idle()
   853  }
   854  
   855  // checkWildcardVersions reports an error if any module in the build list has a
   856  // path (or contains a package) matching a query with a wildcard pattern, but
   857  // has a selected version that does *not* match the query.
   858  func (r *resolver) checkWildcardVersions(ctx context.Context) {
   859  	defer base.ExitIfErrors()
   860  
   861  	for _, q := range r.wildcardQueries {
   862  		for _, curM := range r.buildList {
   863  			if !q.canMatchInModule(curM.Path) {
   864  				continue
   865  			}
   866  			if !q.matchesPath(curM.Path) {
   867  				packages, err := r.matchInModule(ctx, q.pattern, curM)
   868  				if len(packages) == 0 {
   869  					if err != nil {
   870  						reportError(q, err)
   871  					}
   872  					continue // curM is not relevant to q.
   873  				}
   874  			}
   875  
   876  			rev, err := r.queryModule(ctx, curM.Path, q.version, r.initialSelected)
   877  			if err != nil {
   878  				reportError(q, err)
   879  				continue
   880  			}
   881  			if rev.Version == curM.Version {
   882  				continue // curM already matches q.
   883  			}
   884  
   885  			if !q.matchesPath(curM.Path) {
   886  				m := module.Version{Path: curM.Path, Version: rev.Version}
   887  				packages, err := r.matchInModule(ctx, q.pattern, m)
   888  				if err != nil {
   889  					reportError(q, err)
   890  					continue
   891  				}
   892  				if len(packages) == 0 {
   893  					// curM at its original version contains a path matching q.pattern,
   894  					// but at rev.Version it does not, so (somewhat paradoxically) if
   895  					// we changed the version of curM it would no longer match the query.
   896  					var version any = m
   897  					if rev.Version != q.version {
   898  						version = fmt.Sprintf("%s@%s (%s)", m.Path, q.version, m.Version)
   899  					}
   900  					reportError(q, fmt.Errorf("%v matches packages in %v but not %v: specify a different version for module %s", q, curM, version, m.Path))
   901  					continue
   902  				}
   903  			}
   904  
   905  			// Since queryModule succeeded and either curM or one of the packages it
   906  			// contains matches q.pattern, we should have either selected the version
   907  			// of curM matching q, or reported a conflict error (and exited).
   908  			// If we're still here and the version doesn't match,
   909  			// something has gone very wrong.
   910  			reportError(q, fmt.Errorf("internal error: selected %v instead of %v", curM, rev.Version))
   911  		}
   912  	}
   913  }
   914  
   915  // performPathQueries populates the candidates for each query whose pattern is
   916  // a path literal.
   917  //
   918  // The candidate packages and modules for path literals depend only on the
   919  // initial build list, not the current build list, so we only need to query path
   920  // literals once.
   921  func (r *resolver) performPathQueries(ctx context.Context) {
   922  	for _, q := range r.pathQueries {
   923  		q := q
   924  		r.work.Add(func() {
   925  			if q.version == "none" {
   926  				r.queryNone(ctx, q)
   927  			} else {
   928  				r.queryPath(ctx, q)
   929  			}
   930  		})
   931  	}
   932  	<-r.work.Idle()
   933  }
   934  
   935  // queryPath adds a candidate set to q for the package with path q.pattern.
   936  // The candidate set consists of all modules that could provide q.pattern
   937  // and have a version matching q, plus (if it exists) the module whose path
   938  // is itself q.pattern (at a matching version).
   939  func (r *resolver) queryPath(ctx context.Context, q *query) {
   940  	q.pathOnce(q.pattern, func() pathSet {
   941  		if search.IsMetaPackage(q.pattern) || q.isWildcard() {
   942  			panic(fmt.Sprintf("internal error: queryPath called with pattern %q", q.pattern))
   943  		}
   944  		if q.version == "none" {
   945  			panic(`internal error: queryPath called with version "none"`)
   946  		}
   947  
   948  		if search.IsStandardImportPath(q.pattern) {
   949  			stdOnly := module.Version{}
   950  			packages, _ := r.matchInModule(ctx, q.pattern, stdOnly)
   951  			if len(packages) > 0 {
   952  				if q.rawVersion != "" {
   953  					return errSet(fmt.Errorf("can't request explicit version %q of standard library package %s", q.version, q.pattern))
   954  				}
   955  
   956  				q.matchesPackages = true
   957  				return pathSet{} // No module needed for standard library.
   958  			}
   959  		}
   960  
   961  		pkgMods, mod, err := r.queryPattern(ctx, q.pattern, q.version, r.initialSelected)
   962  		if err != nil {
   963  			return errSet(err)
   964  		}
   965  		return pathSet{pkgMods: pkgMods, mod: mod}
   966  	})
   967  }
   968  
   969  // performPatternAllQueries populates the candidates for each query whose
   970  // pattern is "all".
   971  //
   972  // The candidate modules for a given package in "all" depend only on the initial
   973  // build list, but we cannot follow the dependencies of a given package until we
   974  // know which candidate is selected — and that selection may depend on the
   975  // results of other queries. We need to re-evaluate the "all" queries whenever
   976  // the module for one or more packages in "all" are resolved.
   977  func (r *resolver) performPatternAllQueries(ctx context.Context) {
   978  	if len(r.patternAllQueries) == 0 {
   979  		return
   980  	}
   981  
   982  	findPackage := func(ctx context.Context, path string, m module.Version) (versionOk bool) {
   983  		versionOk = true
   984  		for _, q := range r.patternAllQueries {
   985  			q.pathOnce(path, func() pathSet {
   986  				pkgMods, err := r.queryPackages(ctx, path, q.version, r.initialSelected)
   987  				if len(pkgMods) != 1 || pkgMods[0] != m {
   988  					// There are candidates other than m for the given path, so we can't
   989  					// be certain that m will actually be the module selected to provide
   990  					// the package. Don't load its dependencies just yet, because they
   991  					// might no longer be dependencies after we resolve the correct
   992  					// version.
   993  					versionOk = false
   994  				}
   995  				return pathSet{pkgMods: pkgMods, err: err}
   996  			})
   997  		}
   998  		return versionOk
   999  	}
  1000  
  1001  	r.loadPackages(ctx, []string{"all"}, findPackage)
  1002  
  1003  	// Since we built up the candidate lists concurrently, they may be in a
  1004  	// nondeterministic order. We want 'go get' to be fully deterministic,
  1005  	// including in which errors it chooses to report, so sort the candidates
  1006  	// into a deterministic-but-arbitrary order.
  1007  	for _, q := range r.patternAllQueries {
  1008  		sort.Slice(q.candidates, func(i, j int) bool {
  1009  			return q.candidates[i].path < q.candidates[j].path
  1010  		})
  1011  	}
  1012  }
  1013  
  1014  // findAndUpgradeImports returns a pathSet for each package that is not yet
  1015  // in the build list but is transitively imported by the packages matching the
  1016  // given queries (which must already have been resolved).
  1017  //
  1018  // If the getU flag ("-u") is set, findAndUpgradeImports also returns a
  1019  // pathSet for each module that is not constrained by any other
  1020  // command-line argument and has an available matching upgrade.
  1021  func (r *resolver) findAndUpgradeImports(ctx context.Context, queries []*query) (upgrades []pathSet) {
  1022  	patterns := make([]string, 0, len(queries))
  1023  	for _, q := range queries {
  1024  		if q.matchesPackages {
  1025  			patterns = append(patterns, q.pattern)
  1026  		}
  1027  	}
  1028  	if len(patterns) == 0 {
  1029  		return nil
  1030  	}
  1031  
  1032  	// mu guards concurrent writes to upgrades, which will be sorted
  1033  	// (to restore determinism) after loading.
  1034  	var mu sync.Mutex
  1035  
  1036  	findPackage := func(ctx context.Context, path string, m module.Version) (versionOk bool) {
  1037  		version := "latest"
  1038  		if m.Path != "" {
  1039  			if getU.version == "" {
  1040  				// The user did not request that we upgrade transitive dependencies.
  1041  				return true
  1042  			}
  1043  			if _, ok := r.resolvedVersion[m.Path]; ok {
  1044  				// We cannot upgrade m implicitly because its version is determined by
  1045  				// an explicit pattern argument.
  1046  				return true
  1047  			}
  1048  			version = getU.version
  1049  		}
  1050  
  1051  		// Unlike other queries, the "-u" flag upgrades relative to the build list
  1052  		// after applying changes so far, not the initial build list.
  1053  		// This is for two reasons:
  1054  		//
  1055  		// 	- The "-u" flag intentionally applies to transitive dependencies,
  1056  		// 	  which may not be known or even resolved in advance of applying
  1057  		// 	  other version changes.
  1058  		//
  1059  		// 	- The "-u" flag, unlike other arguments, does not cause version
  1060  		// 	  conflicts with other queries. (The other query always wins.)
  1061  
  1062  		pkgMods, err := r.queryPackages(ctx, path, version, r.selected)
  1063  		for _, u := range pkgMods {
  1064  			if u == m {
  1065  				// The selected package version is already upgraded appropriately; there
  1066  				// is no need to change it.
  1067  				return true
  1068  			}
  1069  		}
  1070  
  1071  		if err != nil {
  1072  			if isNoSuchPackageVersion(err) || (m.Path == "" && module.CheckPath(path) != nil) {
  1073  				// We can't find the package because it doesn't — or can't — even exist
  1074  				// in any module at the latest version. (Note that invalid module paths
  1075  				// could in general exist due to replacements, so we at least need to
  1076  				// run the query to check those.)
  1077  				//
  1078  				// There is no version change we can make to fix the package, so leave
  1079  				// it unresolved. Either some other query (perhaps a wildcard matching a
  1080  				// newly-added dependency for some other missing package) will fill in
  1081  				// the gaps, or we will report an error (with a better import stack) in
  1082  				// the final LoadPackages call.
  1083  				return true
  1084  			}
  1085  		}
  1086  
  1087  		mu.Lock()
  1088  		upgrades = append(upgrades, pathSet{path: path, pkgMods: pkgMods, err: err})
  1089  		mu.Unlock()
  1090  		return false
  1091  	}
  1092  
  1093  	r.loadPackages(ctx, patterns, findPackage)
  1094  
  1095  	// Since we built up the candidate lists concurrently, they may be in a
  1096  	// nondeterministic order. We want 'go get' to be fully deterministic,
  1097  	// including in which errors it chooses to report, so sort the candidates
  1098  	// into a deterministic-but-arbitrary order.
  1099  	sort.Slice(upgrades, func(i, j int) bool {
  1100  		return upgrades[i].path < upgrades[j].path
  1101  	})
  1102  	return upgrades
  1103  }
  1104  
  1105  // loadPackages loads the packages matching the given patterns, invoking the
  1106  // findPackage function for each package that may require a change to the
  1107  // build list.
  1108  //
  1109  // loadPackages invokes the findPackage function for each package loaded from a
  1110  // module outside the main module. If the module or version that supplies that
  1111  // package needs to be changed due to a query, findPackage may return false
  1112  // and the imports of that package will not be loaded.
  1113  //
  1114  // loadPackages also invokes the findPackage function for each imported package
  1115  // that is neither present in the standard library nor in any module in the
  1116  // build list.
  1117  func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPackage func(ctx context.Context, path string, m module.Version) (versionOk bool)) {
  1118  	opts := modload.PackageOpts{
  1119  		Tags:                     imports.AnyTags(),
  1120  		VendorModulesInGOROOTSrc: true,
  1121  		LoadTests:                *getT,
  1122  		AssumeRootsImported:      true, // After 'go get foo', imports of foo should build.
  1123  		SilencePackageErrors:     true, // May be fixed by subsequent upgrades or downgrades.
  1124  	}
  1125  
  1126  	opts.AllowPackage = func(ctx context.Context, path string, m module.Version) error {
  1127  		if m.Path == "" || m.Version == "" {
  1128  			// Packages in the standard library and main modules are already at their
  1129  			// latest (and only) available versions.
  1130  			return nil
  1131  		}
  1132  		if ok := findPackage(ctx, path, m); !ok {
  1133  			return errVersionChange
  1134  		}
  1135  		return nil
  1136  	}
  1137  
  1138  	_, pkgs := modload.LoadPackages(ctx, opts, patterns...)
  1139  	for _, path := range pkgs {
  1140  		const (
  1141  			parentPath  = ""
  1142  			parentIsStd = false
  1143  		)
  1144  		_, _, err := modload.Lookup(parentPath, parentIsStd, path)
  1145  		if err == nil {
  1146  			continue
  1147  		}
  1148  		if errors.Is(err, errVersionChange) {
  1149  			// We already added candidates during loading.
  1150  			continue
  1151  		}
  1152  
  1153  		var (
  1154  			importMissing *modload.ImportMissingError
  1155  			ambiguous     *modload.AmbiguousImportError
  1156  		)
  1157  		if !errors.As(err, &importMissing) && !errors.As(err, &ambiguous) {
  1158  			// The package, which is a dependency of something we care about, has some
  1159  			// problem that we can't resolve with a version change.
  1160  			// Leave the error for the final LoadPackages call.
  1161  			continue
  1162  		}
  1163  
  1164  		path := path
  1165  		r.work.Add(func() {
  1166  			findPackage(ctx, path, module.Version{})
  1167  		})
  1168  	}
  1169  	<-r.work.Idle()
  1170  }
  1171  
  1172  // errVersionChange is a sentinel error indicating that a module's version needs
  1173  // to be updated before its dependencies can be loaded.
  1174  var errVersionChange = errors.New("version change needed")
  1175  
  1176  // resolveQueries resolves candidate sets that are attached to the given
  1177  // queries and/or needed to provide the given missing-package dependencies.
  1178  //
  1179  // resolveQueries starts by resolving one module version from each
  1180  // unambiguous pathSet attached to the given queries.
  1181  //
  1182  // If no unambiguous query results in a change to the build list,
  1183  // resolveQueries revisits the ambiguous query candidates and resolves them
  1184  // arbitrarily in order to guarantee forward progress.
  1185  //
  1186  // If all pathSets are resolved without any changes to the build list,
  1187  // resolveQueries returns with changed=false.
  1188  func (r *resolver) resolveQueries(ctx context.Context, queries []*query) (changed bool) {
  1189  	defer base.ExitIfErrors()
  1190  
  1191  	// Note: this is O(N²) with the number of pathSets in the worst case.
  1192  	//
  1193  	// We could perhaps get it down to O(N) if we were to index the pathSets
  1194  	// by module path, so that we only revisit a given pathSet when the
  1195  	// version of some module in its containingPackage list has been determined.
  1196  	//
  1197  	// However, N tends to be small, and most candidate sets will include only one
  1198  	// candidate module (so they will be resolved in the first iteration), so for
  1199  	// now we'll stick to the simple O(N²) approach.
  1200  
  1201  	resolved := 0
  1202  	for {
  1203  		prevResolved := resolved
  1204  
  1205  		for _, q := range queries {
  1206  			unresolved := q.candidates[:0]
  1207  
  1208  			for _, cs := range q.candidates {
  1209  				if cs.err != nil {
  1210  					reportError(q, cs.err)
  1211  					resolved++
  1212  					continue
  1213  				}
  1214  
  1215  				filtered, isPackage, m, unique := r.disambiguate(cs)
  1216  				if !unique {
  1217  					unresolved = append(unresolved, filtered)
  1218  					continue
  1219  				}
  1220  
  1221  				if m.Path == "" {
  1222  					// The query is not viable. Choose an arbitrary candidate from
  1223  					// before filtering and “resolve” it to report a conflict.
  1224  					isPackage, m = r.chooseArbitrarily(cs)
  1225  				}
  1226  				if isPackage {
  1227  					q.matchesPackages = true
  1228  				}
  1229  				r.resolve(q, m)
  1230  				resolved++
  1231  			}
  1232  
  1233  			q.candidates = unresolved
  1234  		}
  1235  
  1236  		base.ExitIfErrors()
  1237  		if resolved == prevResolved {
  1238  			break // No unambiguous candidate remains.
  1239  		}
  1240  	}
  1241  
  1242  	if resolved > 0 {
  1243  		if changed = r.updateBuildList(ctx, nil); changed {
  1244  			// The build list has changed, so disregard any remaining ambiguous queries:
  1245  			// they might now be determined by requirements in the build list, which we
  1246  			// would prefer to use instead of arbitrary versions.
  1247  			return true
  1248  		}
  1249  	}
  1250  
  1251  	// The build list will be the same on the next iteration as it was on this
  1252  	// iteration, so any ambiguous queries will remain so. In order to make
  1253  	// progress, resolve them arbitrarily but deterministically.
  1254  	//
  1255  	// If that results in conflicting versions, the user can re-run 'go get'
  1256  	// with additional explicit versions for the conflicting packages or
  1257  	// modules.
  1258  	resolvedArbitrarily := 0
  1259  	for _, q := range queries {
  1260  		for _, cs := range q.candidates {
  1261  			isPackage, m := r.chooseArbitrarily(cs)
  1262  			if isPackage {
  1263  				q.matchesPackages = true
  1264  			}
  1265  			r.resolve(q, m)
  1266  			resolvedArbitrarily++
  1267  		}
  1268  	}
  1269  	if resolvedArbitrarily > 0 {
  1270  		changed = r.updateBuildList(ctx, nil)
  1271  	}
  1272  	return changed
  1273  }
  1274  
  1275  // applyUpgrades disambiguates candidate sets that are needed to upgrade (or
  1276  // provide) transitive dependencies imported by previously-resolved packages.
  1277  //
  1278  // applyUpgrades modifies the build list by adding one module version from each
  1279  // pathSet in upgrades, then downgrading (or further upgrading) those modules as
  1280  // needed to maintain any already-resolved versions of other modules.
  1281  // applyUpgrades does not mark the new versions as resolved, so they can still
  1282  // be further modified by other queries (such as wildcards).
  1283  //
  1284  // If all pathSets are resolved without any changes to the build list,
  1285  // applyUpgrades returns with changed=false.
  1286  func (r *resolver) applyUpgrades(ctx context.Context, upgrades []pathSet) (changed bool) {
  1287  	defer base.ExitIfErrors()
  1288  
  1289  	// Arbitrarily add a "latest" version that provides each missing package, but
  1290  	// do not mark the version as resolved: we still want to allow the explicit
  1291  	// queries to modify the resulting versions.
  1292  	var tentative []module.Version
  1293  	for _, cs := range upgrades {
  1294  		if cs.err != nil {
  1295  			base.Errorf("go: %v", cs.err)
  1296  			continue
  1297  		}
  1298  
  1299  		filtered, _, m, unique := r.disambiguate(cs)
  1300  		if !unique {
  1301  			_, m = r.chooseArbitrarily(filtered)
  1302  		}
  1303  		if m.Path == "" {
  1304  			// There is no viable candidate for the missing package.
  1305  			// Leave it unresolved.
  1306  			continue
  1307  		}
  1308  		tentative = append(tentative, m)
  1309  	}
  1310  	base.ExitIfErrors()
  1311  
  1312  	changed = r.updateBuildList(ctx, tentative)
  1313  	return changed
  1314  }
  1315  
  1316  // disambiguate eliminates candidates from cs that conflict with other module
  1317  // versions that have already been resolved. If there is only one (unique)
  1318  // remaining candidate, disambiguate returns that candidate, along with
  1319  // an indication of whether that result interprets cs.path as a package
  1320  //
  1321  // Note: we're only doing very simple disambiguation here. The goal is to
  1322  // reproduce the user's intent, not to find a solution that a human couldn't.
  1323  // In the vast majority of cases, we expect only one module per pathSet,
  1324  // but we want to give some minimal additional tools so that users can add an
  1325  // extra argument or two on the command line to resolve simple ambiguities.
  1326  func (r *resolver) disambiguate(cs pathSet) (filtered pathSet, isPackage bool, m module.Version, unique bool) {
  1327  	if len(cs.pkgMods) == 0 && cs.mod.Path == "" {
  1328  		panic("internal error: resolveIfUnambiguous called with empty pathSet")
  1329  	}
  1330  
  1331  	for _, m := range cs.pkgMods {
  1332  		if _, ok := r.noneForPath(m.Path); ok {
  1333  			// A query with version "none" forces the candidate module to version
  1334  			// "none", so we cannot use any other version for that module.
  1335  			continue
  1336  		}
  1337  
  1338  		if modload.MainModules.Contains(m.Path) {
  1339  			if m.Version == "" {
  1340  				return pathSet{}, true, m, true
  1341  			}
  1342  			// A main module can only be set to its own version.
  1343  			continue
  1344  		}
  1345  
  1346  		vr, ok := r.resolvedVersion[m.Path]
  1347  		if !ok {
  1348  			// m is a viable answer to the query, but other answers may also
  1349  			// still be viable.
  1350  			filtered.pkgMods = append(filtered.pkgMods, m)
  1351  			continue
  1352  		}
  1353  
  1354  		if vr.version != m.Version {
  1355  			// Some query forces the candidate module to a version other than this
  1356  			// one.
  1357  			//
  1358  			// The command could be something like
  1359  			//
  1360  			// 	go get example.com/foo/bar@none example.com/foo/bar/baz@latest
  1361  			//
  1362  			// in which case we *cannot* resolve the package from
  1363  			// example.com/foo/bar (because it is constrained to version
  1364  			// "none") and must fall through to module example.com/foo@latest.
  1365  			continue
  1366  		}
  1367  
  1368  		// Some query forces the candidate module *to* the candidate version.
  1369  		// As a result, this candidate is the only viable choice to provide
  1370  		// its package(s): any other choice would result in an ambiguous import
  1371  		// for this path.
  1372  		//
  1373  		// For example, consider the command
  1374  		//
  1375  		// 	go get example.com/foo@latest example.com/foo/bar/baz@latest
  1376  		//
  1377  		// If modules example.com/foo and example.com/foo/bar both provide
  1378  		// package example.com/foo/bar/baz, then we *must* resolve the package
  1379  		// from example.com/foo: if we instead resolved it from
  1380  		// example.com/foo/bar, we would have two copies of the package.
  1381  		return pathSet{}, true, m, true
  1382  	}
  1383  
  1384  	if cs.mod.Path != "" {
  1385  		vr, ok := r.resolvedVersion[cs.mod.Path]
  1386  		if !ok || vr.version == cs.mod.Version {
  1387  			filtered.mod = cs.mod
  1388  		}
  1389  	}
  1390  
  1391  	if len(filtered.pkgMods) == 1 &&
  1392  		(filtered.mod.Path == "" || filtered.mod == filtered.pkgMods[0]) {
  1393  		// Exactly one viable module contains the package with the given path
  1394  		// (by far the common case), so we can resolve it unambiguously.
  1395  		return pathSet{}, true, filtered.pkgMods[0], true
  1396  	}
  1397  
  1398  	if len(filtered.pkgMods) == 0 {
  1399  		// All modules that could provide the path as a package conflict with other
  1400  		// resolved arguments. If it can refer to a module instead, return that;
  1401  		// otherwise, this pathSet cannot be resolved (and we will return the
  1402  		// zero module.Version).
  1403  		return pathSet{}, false, filtered.mod, true
  1404  	}
  1405  
  1406  	// The query remains ambiguous: there are at least two different modules
  1407  	// to which cs.path could refer.
  1408  	return filtered, false, module.Version{}, false
  1409  }
  1410  
  1411  // chooseArbitrarily returns an arbitrary (but deterministic) module version
  1412  // from among those in the given set.
  1413  //
  1414  // chooseArbitrarily prefers module paths that were already in the build list at
  1415  // the start of 'go get', prefers modules that provide packages over those that
  1416  // do not, and chooses the first module meeting those criteria (so biases toward
  1417  // longer paths).
  1418  func (r *resolver) chooseArbitrarily(cs pathSet) (isPackage bool, m module.Version) {
  1419  	// Prefer to upgrade some module that was already in the build list.
  1420  	for _, m := range cs.pkgMods {
  1421  		if r.initialSelected(m.Path) != "none" {
  1422  			return true, m
  1423  		}
  1424  	}
  1425  
  1426  	// Otherwise, arbitrarily choose the first module that provides the package.
  1427  	if len(cs.pkgMods) > 0 {
  1428  		return true, cs.pkgMods[0]
  1429  	}
  1430  
  1431  	return false, cs.mod
  1432  }
  1433  
  1434  // checkPackageProblems reloads packages for the given patterns and reports
  1435  // missing and ambiguous package errors. It also reports retractions and
  1436  // deprecations for resolved modules and modules needed to build named packages.
  1437  // It also adds a sum for each updated module in the build list if we had one
  1438  // before and didn't get one while loading packages.
  1439  //
  1440  // We skip missing-package errors earlier in the process, since we want to
  1441  // resolve pathSets ourselves, but at that point, we don't have enough context
  1442  // to log the package-import chains leading to each error.
  1443  func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []string) {
  1444  	defer base.ExitIfErrors()
  1445  
  1446  	// Gather information about modules we might want to load retractions and
  1447  	// deprecations for. Loading this metadata requires at least one version
  1448  	// lookup per module, and we don't want to load information that's neither
  1449  	// relevant nor actionable.
  1450  	type modFlags int
  1451  	const (
  1452  		resolved modFlags = 1 << iota // version resolved by 'go get'
  1453  		named                         // explicitly named on command line or provides a named package
  1454  		hasPkg                        // needed to build named packages
  1455  		direct                        // provides a direct dependency of the main module
  1456  	)
  1457  	relevantMods := make(map[module.Version]modFlags)
  1458  	for path, reason := range r.resolvedVersion {
  1459  		m := module.Version{Path: path, Version: reason.version}
  1460  		relevantMods[m] |= resolved
  1461  	}
  1462  
  1463  	// Reload packages, reporting errors for missing and ambiguous imports.
  1464  	if len(pkgPatterns) > 0 {
  1465  		// LoadPackages will print errors (since it has more context) but will not
  1466  		// exit, since we need to load retractions later.
  1467  		pkgOpts := modload.PackageOpts{
  1468  			VendorModulesInGOROOTSrc: true,
  1469  			LoadTests:                *getT,
  1470  			ResolveMissingImports:    false,
  1471  			AllowErrors:              true,
  1472  			SilenceNoGoErrors:        true,
  1473  		}
  1474  		matches, pkgs := modload.LoadPackages(ctx, pkgOpts, pkgPatterns...)
  1475  		for _, m := range matches {
  1476  			if len(m.Errs) > 0 {
  1477  				base.SetExitStatus(1)
  1478  				break
  1479  			}
  1480  		}
  1481  		for _, pkg := range pkgs {
  1482  			if dir, _, err := modload.Lookup("", false, pkg); err != nil {
  1483  				if dir != "" && errors.Is(err, imports.ErrNoGo) {
  1484  					// Since dir is non-empty, we must have located source files
  1485  					// associated with either the package or its test — ErrNoGo must
  1486  					// indicate that none of those source files happen to apply in this
  1487  					// configuration. If we are actually building the package (no -d
  1488  					// flag), we will report the problem then; otherwise, assume that the
  1489  					// user is going to build or test this package in some other
  1490  					// configuration and suppress the error.
  1491  					continue
  1492  				}
  1493  
  1494  				base.SetExitStatus(1)
  1495  				if ambiguousErr := (*modload.AmbiguousImportError)(nil); errors.As(err, &ambiguousErr) {
  1496  					for _, m := range ambiguousErr.Modules {
  1497  						relevantMods[m] |= hasPkg
  1498  					}
  1499  				}
  1500  			}
  1501  			if m := modload.PackageModule(pkg); m.Path != "" {
  1502  				relevantMods[m] |= hasPkg
  1503  			}
  1504  		}
  1505  		for _, match := range matches {
  1506  			for _, pkg := range match.Pkgs {
  1507  				m := modload.PackageModule(pkg)
  1508  				relevantMods[m] |= named
  1509  			}
  1510  		}
  1511  	}
  1512  
  1513  	reqs := modload.LoadModFile(ctx)
  1514  	for m := range relevantMods {
  1515  		if reqs.IsDirect(m.Path) {
  1516  			relevantMods[m] |= direct
  1517  		}
  1518  	}
  1519  
  1520  	// Load retractions for modules mentioned on the command line and modules
  1521  	// needed to build named packages. We care about retractions of indirect
  1522  	// dependencies, since we might be able to upgrade away from them.
  1523  	type modMessage struct {
  1524  		m       module.Version
  1525  		message string
  1526  	}
  1527  	retractions := make([]modMessage, 0, len(relevantMods))
  1528  	for m, flags := range relevantMods {
  1529  		if flags&(resolved|named|hasPkg) != 0 {
  1530  			retractions = append(retractions, modMessage{m: m})
  1531  		}
  1532  	}
  1533  	sort.Slice(retractions, func(i, j int) bool { return retractions[i].m.Path < retractions[j].m.Path })
  1534  	for i := range retractions {
  1535  		i := i
  1536  		r.work.Add(func() {
  1537  			err := modload.CheckRetractions(ctx, retractions[i].m)
  1538  			if retractErr := (*modload.ModuleRetractedError)(nil); errors.As(err, &retractErr) {
  1539  				retractions[i].message = err.Error()
  1540  			}
  1541  		})
  1542  	}
  1543  
  1544  	// Load deprecations for modules mentioned on the command line. Only load
  1545  	// deprecations for indirect dependencies if they're also direct dependencies
  1546  	// of the main module. Deprecations of purely indirect dependencies are
  1547  	// not actionable.
  1548  	deprecations := make([]modMessage, 0, len(relevantMods))
  1549  	for m, flags := range relevantMods {
  1550  		if flags&(resolved|named) != 0 || flags&(hasPkg|direct) == hasPkg|direct {
  1551  			deprecations = append(deprecations, modMessage{m: m})
  1552  		}
  1553  	}
  1554  	sort.Slice(deprecations, func(i, j int) bool { return deprecations[i].m.Path < deprecations[j].m.Path })
  1555  	for i := range deprecations {
  1556  		i := i
  1557  		r.work.Add(func() {
  1558  			deprecation, err := modload.CheckDeprecation(ctx, deprecations[i].m)
  1559  			if err != nil || deprecation == "" {
  1560  				return
  1561  			}
  1562  			deprecations[i].message = modload.ShortMessage(deprecation, "")
  1563  		})
  1564  	}
  1565  
  1566  	// Load sums for updated modules that had sums before. When we update a
  1567  	// module, we may update another module in the build list that provides a
  1568  	// package in 'all' that wasn't loaded as part of this 'go get' command.
  1569  	// If we don't add a sum for that module, builds may fail later.
  1570  	// Note that an incidentally updated package could still import packages
  1571  	// from unknown modules or from modules in the build list that we didn't
  1572  	// need previously. We can't handle that case without loading 'all'.
  1573  	sumErrs := make([]error, len(r.buildList))
  1574  	for i := range r.buildList {
  1575  		i := i
  1576  		m := r.buildList[i]
  1577  		mActual := m
  1578  		if mRepl := modload.Replacement(m); mRepl.Path != "" {
  1579  			mActual = mRepl
  1580  		}
  1581  		old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]}
  1582  		if old.Version == "" {
  1583  			continue
  1584  		}
  1585  		oldActual := old
  1586  		if oldRepl := modload.Replacement(old); oldRepl.Path != "" {
  1587  			oldActual = oldRepl
  1588  		}
  1589  		if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(oldActual) {
  1590  			continue
  1591  		}
  1592  		r.work.Add(func() {
  1593  			if _, err := modfetch.DownloadZip(ctx, mActual); err != nil {
  1594  				verb := "upgraded"
  1595  				if semver.Compare(m.Version, old.Version) < 0 {
  1596  					verb = "downgraded"
  1597  				}
  1598  				replaced := ""
  1599  				if mActual != m {
  1600  					replaced = fmt.Sprintf(" (replaced by %s)", mActual)
  1601  				}
  1602  				err = fmt.Errorf("%s %s %s => %s%s: error finding sum for %s: %v", verb, m.Path, old.Version, m.Version, replaced, mActual, err)
  1603  				sumErrs[i] = err
  1604  			}
  1605  		})
  1606  	}
  1607  
  1608  	<-r.work.Idle()
  1609  
  1610  	// Report deprecations, then retractions, then errors fetching sums.
  1611  	// Only errors fetching sums are hard errors.
  1612  	for _, mm := range deprecations {
  1613  		if mm.message != "" {
  1614  			fmt.Fprintf(os.Stderr, "go: module %s is deprecated: %s\n", mm.m.Path, mm.message)
  1615  		}
  1616  	}
  1617  	var retractPath string
  1618  	for _, mm := range retractions {
  1619  		if mm.message != "" {
  1620  			fmt.Fprintf(os.Stderr, "go: warning: %v\n", mm.message)
  1621  			if retractPath == "" {
  1622  				retractPath = mm.m.Path
  1623  			} else {
  1624  				retractPath = "<module>"
  1625  			}
  1626  		}
  1627  	}
  1628  	if retractPath != "" {
  1629  		fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath)
  1630  	}
  1631  	for _, err := range sumErrs {
  1632  		if err != nil {
  1633  			base.Errorf("go: %v", err)
  1634  		}
  1635  	}
  1636  	base.ExitIfErrors()
  1637  }
  1638  
  1639  // reportChanges logs version changes to os.Stderr.
  1640  //
  1641  // reportChanges only logs changes to modules named on the command line and to
  1642  // explicitly required modules in go.mod. Most changes to indirect requirements
  1643  // are not relevant to the user and are not logged.
  1644  //
  1645  // reportChanges should be called after WriteGoMod.
  1646  func (r *resolver) reportChanges(oldReqs, newReqs []module.Version) {
  1647  	type change struct {
  1648  		path, old, new string
  1649  	}
  1650  	changes := make(map[string]change)
  1651  
  1652  	// Collect changes in modules matched by command line arguments.
  1653  	for path, reason := range r.resolvedVersion {
  1654  		old := r.initialVersion[path]
  1655  		new := reason.version
  1656  		if old != new && (old != "" || new != "none") {
  1657  			changes[path] = change{path, old, new}
  1658  		}
  1659  	}
  1660  
  1661  	// Collect changes to explicit requirements in go.mod.
  1662  	for _, req := range oldReqs {
  1663  		path := req.Path
  1664  		old := req.Version
  1665  		new := r.buildListVersion[path]
  1666  		if old != new {
  1667  			changes[path] = change{path, old, new}
  1668  		}
  1669  	}
  1670  	for _, req := range newReqs {
  1671  		path := req.Path
  1672  		old := r.initialVersion[path]
  1673  		new := req.Version
  1674  		if old != new {
  1675  			changes[path] = change{path, old, new}
  1676  		}
  1677  	}
  1678  
  1679  	sortedChanges := make([]change, 0, len(changes))
  1680  	for _, c := range changes {
  1681  		sortedChanges = append(sortedChanges, c)
  1682  	}
  1683  	sort.Slice(sortedChanges, func(i, j int) bool {
  1684  		return sortedChanges[i].path < sortedChanges[j].path
  1685  	})
  1686  	for _, c := range sortedChanges {
  1687  		if c.old == "" {
  1688  			fmt.Fprintf(os.Stderr, "go: added %s %s\n", c.path, c.new)
  1689  		} else if c.new == "none" || c.new == "" {
  1690  			fmt.Fprintf(os.Stderr, "go: removed %s %s\n", c.path, c.old)
  1691  		} else if semver.Compare(c.new, c.old) > 0 {
  1692  			fmt.Fprintf(os.Stderr, "go: upgraded %s %s => %s\n", c.path, c.old, c.new)
  1693  		} else {
  1694  			fmt.Fprintf(os.Stderr, "go: downgraded %s %s => %s\n", c.path, c.old, c.new)
  1695  		}
  1696  	}
  1697  
  1698  	// TODO(golang.org/issue/33284): attribute changes to command line arguments.
  1699  	// For modules matched by command line arguments, this probably isn't
  1700  	// necessary, but it would be useful for unmatched direct dependencies of
  1701  	// the main module.
  1702  }
  1703  
  1704  // resolve records that module m must be at its indicated version (which may be
  1705  // "none") due to query q. If some other query forces module m to be at a
  1706  // different version, resolve reports a conflict error.
  1707  func (r *resolver) resolve(q *query, m module.Version) {
  1708  	if m.Path == "" {
  1709  		panic("internal error: resolving a module.Version with an empty path")
  1710  	}
  1711  
  1712  	if modload.MainModules.Contains(m.Path) && m.Version != "" {
  1713  		reportError(q, &modload.QueryMatchesMainModulesError{
  1714  			MainModules: []module.Version{{Path: m.Path}},
  1715  			Pattern:     q.pattern,
  1716  			Query:       q.version,
  1717  		})
  1718  		return
  1719  	}
  1720  
  1721  	vr, ok := r.resolvedVersion[m.Path]
  1722  	if ok && vr.version != m.Version {
  1723  		reportConflict(q, m, vr)
  1724  		return
  1725  	}
  1726  	r.resolvedVersion[m.Path] = versionReason{m.Version, q}
  1727  	q.resolved = append(q.resolved, m)
  1728  }
  1729  
  1730  // updateBuildList updates the module loader's global build list to be
  1731  // consistent with r.resolvedVersion, and to include additional modules
  1732  // provided that they do not conflict with the resolved versions.
  1733  //
  1734  // If the additional modules conflict with the resolved versions, they will be
  1735  // downgraded to a non-conflicting version (possibly "none").
  1736  //
  1737  // If the resulting build list is the same as the one resulting from the last
  1738  // call to updateBuildList, updateBuildList returns with changed=false.
  1739  func (r *resolver) updateBuildList(ctx context.Context, additions []module.Version) (changed bool) {
  1740  	defer base.ExitIfErrors()
  1741  
  1742  	resolved := make([]module.Version, 0, len(r.resolvedVersion))
  1743  	for mPath, rv := range r.resolvedVersion {
  1744  		if !modload.MainModules.Contains(mPath) {
  1745  			resolved = append(resolved, module.Version{Path: mPath, Version: rv.version})
  1746  		}
  1747  	}
  1748  
  1749  	changed, err := modload.EditBuildList(ctx, additions, resolved)
  1750  	if err != nil {
  1751  		var constraint *modload.ConstraintError
  1752  		if !errors.As(err, &constraint) {
  1753  			base.Errorf("go: %v", err)
  1754  			return false
  1755  		}
  1756  
  1757  		reason := func(m module.Version) string {
  1758  			rv, ok := r.resolvedVersion[m.Path]
  1759  			if !ok {
  1760  				panic(fmt.Sprintf("internal error: can't find reason for requirement on %v", m))
  1761  			}
  1762  			return rv.reason.ResolvedString(module.Version{Path: m.Path, Version: rv.version})
  1763  		}
  1764  		for _, c := range constraint.Conflicts {
  1765  			base.Errorf("go: %v requires %v, not %v", reason(c.Source), c.Dep, reason(c.Constraint))
  1766  		}
  1767  		return false
  1768  	}
  1769  	if !changed {
  1770  		return false
  1771  	}
  1772  
  1773  	const defaultGoVersion = ""
  1774  	r.buildList = modload.LoadModGraph(ctx, defaultGoVersion).BuildList()
  1775  	r.buildListVersion = make(map[string]string, len(r.buildList))
  1776  	for _, m := range r.buildList {
  1777  		r.buildListVersion[m.Path] = m.Version
  1778  	}
  1779  	return true
  1780  }
  1781  
  1782  func reqsFromGoMod(f *modfile.File) []module.Version {
  1783  	reqs := make([]module.Version, len(f.Require))
  1784  	for i, r := range f.Require {
  1785  		reqs[i] = r.Mod
  1786  	}
  1787  	return reqs
  1788  }
  1789  
  1790  // isNoSuchModuleVersion reports whether err indicates that the requested module
  1791  // does not exist at the requested version, either because the module does not
  1792  // exist at all or because it does not include that specific version.
  1793  func isNoSuchModuleVersion(err error) bool {
  1794  	var noMatch *modload.NoMatchingVersionError
  1795  	return errors.Is(err, os.ErrNotExist) || errors.As(err, &noMatch)
  1796  }
  1797  
  1798  // isNoSuchPackageVersion reports whether err indicates that the requested
  1799  // package does not exist at the requested version, either because no module
  1800  // that could contain it exists at that version, or because every such module
  1801  // that does exist does not actually contain the package.
  1802  func isNoSuchPackageVersion(err error) bool {
  1803  	var noPackage *modload.PackageNotInModuleError
  1804  	return isNoSuchModuleVersion(err) || errors.As(err, &noPackage)
  1805  }
  1806  

View as plain text