github.com/bir3/gocompiler@v0.3.205/src/cmd/gocmd/internal/modload/query.go (about)

     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 modload
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"errors"
    11  	"fmt"
    12  	"io/fs"
    13  	"os"
    14  	pathpkg "path"
    15  	"sort"
    16  	"strings"
    17  	"sync"
    18  	"time"
    19  
    20  	"github.com/bir3/gocompiler/src/cmd/gocmd/internal/cfg"
    21  	"github.com/bir3/gocompiler/src/cmd/gocmd/internal/imports"
    22  	"github.com/bir3/gocompiler/src/cmd/gocmd/internal/modfetch"
    23  	"github.com/bir3/gocompiler/src/cmd/gocmd/internal/modfetch/codehost"
    24  	"github.com/bir3/gocompiler/src/cmd/gocmd/internal/modinfo"
    25  	"github.com/bir3/gocompiler/src/cmd/gocmd/internal/search"
    26  	"github.com/bir3/gocompiler/src/cmd/gocmd/internal/str"
    27  	"github.com/bir3/gocompiler/src/cmd/gocmd/internal/trace"
    28  	"github.com/bir3/gocompiler/src/cmd/internal/pkgpattern"
    29  
    30  	"github.com/bir3/gocompiler/src/xvendor/golang.org/x/mod/module"
    31  	"github.com/bir3/gocompiler/src/xvendor/golang.org/x/mod/semver"
    32  )
    33  
    34  // Query looks up a revision of a given module given a version query string.
    35  // The module must be a complete module path.
    36  // The version must take one of the following forms:
    37  //
    38  //   - the literal string "latest", denoting the latest available, allowed
    39  //     tagged version, with non-prereleases preferred over prereleases.
    40  //     If there are no tagged versions in the repo, latest returns the most
    41  //     recent commit.
    42  //
    43  //   - the literal string "upgrade", equivalent to "latest" except that if
    44  //     current is a newer version, current will be returned (see below).
    45  //
    46  //   - the literal string "patch", denoting the latest available tagged version
    47  //     with the same major and minor number as current (see below).
    48  //
    49  //   - v1, denoting the latest available tagged version v1.x.x.
    50  //
    51  //   - v1.2, denoting the latest available tagged version v1.2.x.
    52  //
    53  //   - v1.2.3, a semantic version string denoting that tagged version.
    54  //
    55  //   - <v1.2.3, <=v1.2.3, >v1.2.3, >=v1.2.3,
    56  //     denoting the version closest to the target and satisfying the given operator,
    57  //     with non-prereleases preferred over prereleases.
    58  //
    59  //   - a repository commit identifier or tag, denoting that commit.
    60  //
    61  // current denotes the currently-selected version of the module; it may be
    62  // "none" if no version is currently selected, or "" if the currently-selected
    63  // version is unknown or should not be considered. If query is
    64  // "upgrade" or "patch", current will be returned if it is a newer
    65  // semantic version or a chronologically later pseudo-version than the
    66  // version that would otherwise be chosen. This prevents accidental downgrades
    67  // from newer pre-release or development versions.
    68  //
    69  // The allowed function (which may be nil) is used to filter out unsuitable
    70  // versions (see AllowedFunc documentation for details). If the query refers to
    71  // a specific revision (for example, "master"; see IsRevisionQuery), and the
    72  // revision is disallowed by allowed, Query returns the error. If the query
    73  // does not refer to a specific revision (for example, "latest"), Query
    74  // acts as if versions disallowed by allowed do not exist.
    75  //
    76  // If path is the path of the main module and the query is "latest",
    77  // Query returns Target.Version as the version.
    78  //
    79  // Query often returns a non-nil *RevInfo with a non-nil error,
    80  // to provide an info.Origin that can allow the error to be cached.
    81  func Query(ctx context.Context, path, query, current string, allowed AllowedFunc) (*modfetch.RevInfo, error) {
    82  	ctx, span := trace.StartSpan(ctx, "modload.Query "+path)
    83  	defer span.Done()
    84  
    85  	return queryReuse(ctx, path, query, current, allowed, nil)
    86  }
    87  
    88  // queryReuse is like Query but also takes a map of module info that can be reused
    89  // if the validation criteria in Origin are met.
    90  func queryReuse(ctx context.Context, path, query, current string, allowed AllowedFunc, reuse map[module.Version]*modinfo.ModulePublic) (*modfetch.RevInfo, error) {
    91  	var info *modfetch.RevInfo
    92  	err := modfetch.TryProxies(func(proxy string) (err error) {
    93  		info, err = queryProxy(ctx, proxy, path, query, current, allowed, reuse)
    94  		return err
    95  	})
    96  	return info, err
    97  }
    98  
    99  // checkReuse checks whether a revision of a given module or a version list
   100  // for a given module may be reused, according to the information in origin.
   101  func checkReuse(ctx context.Context, path string, old *codehost.Origin) error {
   102  	return modfetch.TryProxies(func(proxy string) error {
   103  		repo, err := lookupRepo(proxy, path)
   104  		if err != nil {
   105  			return err
   106  		}
   107  		return repo.CheckReuse(old)
   108  	})
   109  }
   110  
   111  // AllowedFunc is used by Query and other functions to filter out unsuitable
   112  // versions, for example, those listed in exclude directives in the main
   113  // module's go.mod file.
   114  //
   115  // An AllowedFunc returns an error equivalent to ErrDisallowed for an unsuitable
   116  // version. Any other error indicates the function was unable to determine
   117  // whether the version should be allowed, for example, the function was unable
   118  // to fetch or parse a go.mod file containing retractions. Typically, errors
   119  // other than ErrDisallowd may be ignored.
   120  type AllowedFunc func(context.Context, module.Version) error
   121  
   122  var errQueryDisabled error = queryDisabledError{}
   123  
   124  type queryDisabledError struct{}
   125  
   126  func (queryDisabledError) Error() string {
   127  	if cfg.BuildModReason == "" {
   128  		return fmt.Sprintf("cannot query module due to -mod=%s", cfg.BuildMod)
   129  	}
   130  	return fmt.Sprintf("cannot query module due to -mod=%s\n\t(%s)", cfg.BuildMod, cfg.BuildModReason)
   131  }
   132  
   133  func queryProxy(ctx context.Context, proxy, path, query, current string, allowed AllowedFunc, reuse map[module.Version]*modinfo.ModulePublic) (*modfetch.RevInfo, error) {
   134  	ctx, span := trace.StartSpan(ctx, "modload.queryProxy "+path+" "+query)
   135  	defer span.Done()
   136  
   137  	if current != "" && current != "none" && !semver.IsValid(current) {
   138  		return nil, fmt.Errorf("invalid previous version %q", current)
   139  	}
   140  	if cfg.BuildMod == "vendor" {
   141  		return nil, errQueryDisabled
   142  	}
   143  	if allowed == nil {
   144  		allowed = func(context.Context, module.Version) error { return nil }
   145  	}
   146  
   147  	if MainModules.Contains(path) && (query == "upgrade" || query == "patch") {
   148  		m := module.Version{Path: path}
   149  		if err := allowed(ctx, m); err != nil {
   150  			return nil, fmt.Errorf("internal error: main module version is not allowed: %w", err)
   151  		}
   152  		return &modfetch.RevInfo{Version: m.Version}, nil
   153  	}
   154  
   155  	if path == "std" || path == "cmd" {
   156  		return nil, fmt.Errorf("can't query specific version (%q) of standard-library module %q", query, path)
   157  	}
   158  
   159  	repo, err := lookupRepo(proxy, path)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	if old := reuse[module.Version{Path: path, Version: query}]; old != nil {
   165  		if err := repo.CheckReuse(old.Origin); err == nil {
   166  			info := &modfetch.RevInfo{
   167  				Version: old.Version,
   168  				Origin:  old.Origin,
   169  			}
   170  			if old.Time != nil {
   171  				info.Time = *old.Time
   172  			}
   173  			return info, nil
   174  		}
   175  	}
   176  
   177  	// Parse query to detect parse errors (and possibly handle query)
   178  	// before any network I/O.
   179  	qm, err := newQueryMatcher(path, query, current, allowed)
   180  	if (err == nil && qm.canStat) || err == errRevQuery {
   181  		// Direct lookup of a commit identifier or complete (non-prefix) semantic
   182  		// version.
   183  
   184  		// If the identifier is not a canonical semver tag — including if it's a
   185  		// semver tag with a +metadata suffix — then modfetch.Stat will populate
   186  		// info.Version with a suitable pseudo-version.
   187  		info, err := repo.Stat(query)
   188  		if err != nil {
   189  			queryErr := err
   190  			// The full query doesn't correspond to a tag. If it is a semantic version
   191  			// with a +metadata suffix, see if there is a tag without that suffix:
   192  			// semantic versioning defines them to be equivalent.
   193  			canonicalQuery := module.CanonicalVersion(query)
   194  			if canonicalQuery != "" && query != canonicalQuery {
   195  				info, err = repo.Stat(canonicalQuery)
   196  				if err != nil && !errors.Is(err, fs.ErrNotExist) {
   197  					return info, err
   198  				}
   199  			}
   200  			if err != nil {
   201  				return info, queryErr
   202  			}
   203  		}
   204  		if err := allowed(ctx, module.Version{Path: path, Version: info.Version}); errors.Is(err, ErrDisallowed) {
   205  			return nil, err
   206  		}
   207  		return info, nil
   208  	} else if err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	// Load versions and execute query.
   213  	versions, err := repo.Versions(qm.prefix)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  	revErr := &modfetch.RevInfo{Origin: versions.Origin} // RevInfo to return with error
   218  
   219  	releases, prereleases, err := qm.filterVersions(ctx, versions.List)
   220  	if err != nil {
   221  		return revErr, err
   222  	}
   223  
   224  	mergeRevOrigin := func(rev *modfetch.RevInfo, origin *codehost.Origin) *modfetch.RevInfo {
   225  		merged := mergeOrigin(rev.Origin, origin)
   226  		if merged == rev.Origin {
   227  			return rev
   228  		}
   229  		clone := new(modfetch.RevInfo)
   230  		*clone = *rev
   231  		clone.Origin = merged
   232  		return clone
   233  	}
   234  
   235  	lookup := func(v string) (*modfetch.RevInfo, error) {
   236  		rev, err := repo.Stat(v)
   237  		// Stat can return a non-nil rev and a non-nil err,
   238  		// in order to provide origin information to make the error cacheable.
   239  		if rev == nil && err != nil {
   240  			return revErr, err
   241  		}
   242  		rev = mergeRevOrigin(rev, versions.Origin)
   243  		if err != nil {
   244  			return rev, err
   245  		}
   246  
   247  		if (query == "upgrade" || query == "patch") && module.IsPseudoVersion(current) && !rev.Time.IsZero() {
   248  			// Don't allow "upgrade" or "patch" to move from a pseudo-version
   249  			// to a chronologically older version or pseudo-version.
   250  			//
   251  			// If the current version is a pseudo-version from an untagged branch, it
   252  			// may be semantically lower than the "latest" release or the latest
   253  			// pseudo-version on the main branch. A user on such a version is unlikely
   254  			// to intend to “upgrade” to a version that already existed at that point
   255  			// in time.
   256  			//
   257  			// We do this only if the current version is a pseudo-version: if the
   258  			// version is tagged, the author of the dependency module has given us
   259  			// explicit information about their intended precedence of this version
   260  			// relative to other versions, and we shouldn't contradict that
   261  			// information. (For example, v1.0.1 might be a backport of a fix already
   262  			// incorporated into v1.1.0, in which case v1.0.1 would be chronologically
   263  			// newer but v1.1.0 is still an “upgrade”; or v1.0.2 might be a revert of
   264  			// an unsuccessful fix in v1.0.1, in which case the v1.0.2 commit may be
   265  			// older than the v1.0.1 commit despite the tag itself being newer.)
   266  			currentTime, err := module.PseudoVersionTime(current)
   267  			if err == nil && rev.Time.Before(currentTime) {
   268  				if err := allowed(ctx, module.Version{Path: path, Version: current}); errors.Is(err, ErrDisallowed) {
   269  					return revErr, err
   270  				}
   271  				rev, err = repo.Stat(current)
   272  				if rev == nil && err != nil {
   273  					return revErr, err
   274  				}
   275  				rev = mergeRevOrigin(rev, versions.Origin)
   276  				return rev, err
   277  			}
   278  		}
   279  
   280  		return rev, nil
   281  	}
   282  
   283  	if qm.preferLower {
   284  		if len(releases) > 0 {
   285  			return lookup(releases[0])
   286  		}
   287  		if len(prereleases) > 0 {
   288  			return lookup(prereleases[0])
   289  		}
   290  	} else {
   291  		if len(releases) > 0 {
   292  			return lookup(releases[len(releases)-1])
   293  		}
   294  		if len(prereleases) > 0 {
   295  			return lookup(prereleases[len(prereleases)-1])
   296  		}
   297  	}
   298  
   299  	if qm.mayUseLatest {
   300  		latest, err := repo.Latest()
   301  		if err == nil {
   302  			if qm.allowsVersion(ctx, latest.Version) {
   303  				return lookup(latest.Version)
   304  			}
   305  		} else if !errors.Is(err, fs.ErrNotExist) {
   306  			return revErr, err
   307  		}
   308  	}
   309  
   310  	if (query == "upgrade" || query == "patch") && current != "" && current != "none" {
   311  		// "upgrade" and "patch" may stay on the current version if allowed.
   312  		if err := allowed(ctx, module.Version{Path: path, Version: current}); errors.Is(err, ErrDisallowed) {
   313  			return nil, err
   314  		}
   315  		return lookup(current)
   316  	}
   317  
   318  	return revErr, &NoMatchingVersionError{query: query, current: current}
   319  }
   320  
   321  // IsRevisionQuery returns true if vers is a version query that may refer to
   322  // a particular version or revision in a repository like "v1.0.0", "master",
   323  // or "0123abcd". IsRevisionQuery returns false if vers is a query that
   324  // chooses from among available versions like "latest" or ">v1.0.0".
   325  func IsRevisionQuery(vers string) bool {
   326  	if vers == "latest" ||
   327  		vers == "upgrade" ||
   328  		vers == "patch" ||
   329  		strings.HasPrefix(vers, "<") ||
   330  		strings.HasPrefix(vers, ">") ||
   331  		(semver.IsValid(vers) && isSemverPrefix(vers)) {
   332  		return false
   333  	}
   334  	return true
   335  }
   336  
   337  // isSemverPrefix reports whether v is a semantic version prefix: v1 or v1.2 (not v1.2.3).
   338  // The caller is assumed to have checked that semver.IsValid(v) is true.
   339  func isSemverPrefix(v string) bool {
   340  	dots := 0
   341  	for i := 0; i < len(v); i++ {
   342  		switch v[i] {
   343  		case '-', '+':
   344  			return false
   345  		case '.':
   346  			dots++
   347  			if dots >= 2 {
   348  				return false
   349  			}
   350  		}
   351  	}
   352  	return true
   353  }
   354  
   355  type queryMatcher struct {
   356  	path               string
   357  	prefix             string
   358  	filter             func(version string) bool
   359  	allowed            AllowedFunc
   360  	canStat            bool // if true, the query can be resolved by repo.Stat
   361  	preferLower        bool // if true, choose the lowest matching version
   362  	mayUseLatest       bool
   363  	preferIncompatible bool
   364  }
   365  
   366  var errRevQuery = errors.New("query refers to a non-semver revision")
   367  
   368  // newQueryMatcher returns a new queryMatcher that matches the versions
   369  // specified by the given query on the module with the given path.
   370  //
   371  // If the query can only be resolved by statting a non-SemVer revision,
   372  // newQueryMatcher returns errRevQuery.
   373  func newQueryMatcher(path string, query, current string, allowed AllowedFunc) (*queryMatcher, error) {
   374  	badVersion := func(v string) (*queryMatcher, error) {
   375  		return nil, fmt.Errorf("invalid semantic version %q in range %q", v, query)
   376  	}
   377  
   378  	matchesMajor := func(v string) bool {
   379  		_, pathMajor, ok := module.SplitPathVersion(path)
   380  		if !ok {
   381  			return false
   382  		}
   383  		return module.CheckPathMajor(v, pathMajor) == nil
   384  	}
   385  
   386  	qm := &queryMatcher{
   387  		path:               path,
   388  		allowed:            allowed,
   389  		preferIncompatible: strings.HasSuffix(current, "+incompatible"),
   390  	}
   391  
   392  	switch {
   393  	case query == "latest":
   394  		qm.mayUseLatest = true
   395  
   396  	case query == "upgrade":
   397  		if current == "" || current == "none" {
   398  			qm.mayUseLatest = true
   399  		} else {
   400  			qm.mayUseLatest = module.IsPseudoVersion(current)
   401  			qm.filter = func(mv string) bool { return semver.Compare(mv, current) >= 0 }
   402  		}
   403  
   404  	case query == "patch":
   405  		if current == "" || current == "none" {
   406  			return nil, &NoPatchBaseError{path}
   407  		}
   408  		if current == "" {
   409  			qm.mayUseLatest = true
   410  		} else {
   411  			qm.mayUseLatest = module.IsPseudoVersion(current)
   412  			qm.prefix = semver.MajorMinor(current) + "."
   413  			qm.filter = func(mv string) bool { return semver.Compare(mv, current) >= 0 }
   414  		}
   415  
   416  	case strings.HasPrefix(query, "<="):
   417  		v := query[len("<="):]
   418  		if !semver.IsValid(v) {
   419  			return badVersion(v)
   420  		}
   421  		if isSemverPrefix(v) {
   422  			// Refuse to say whether <=v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3).
   423  			return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query)
   424  		}
   425  		qm.filter = func(mv string) bool { return semver.Compare(mv, v) <= 0 }
   426  		if !matchesMajor(v) {
   427  			qm.preferIncompatible = true
   428  		}
   429  
   430  	case strings.HasPrefix(query, "<"):
   431  		v := query[len("<"):]
   432  		if !semver.IsValid(v) {
   433  			return badVersion(v)
   434  		}
   435  		qm.filter = func(mv string) bool { return semver.Compare(mv, v) < 0 }
   436  		if !matchesMajor(v) {
   437  			qm.preferIncompatible = true
   438  		}
   439  
   440  	case strings.HasPrefix(query, ">="):
   441  		v := query[len(">="):]
   442  		if !semver.IsValid(v) {
   443  			return badVersion(v)
   444  		}
   445  		qm.filter = func(mv string) bool { return semver.Compare(mv, v) >= 0 }
   446  		qm.preferLower = true
   447  		if !matchesMajor(v) {
   448  			qm.preferIncompatible = true
   449  		}
   450  
   451  	case strings.HasPrefix(query, ">"):
   452  		v := query[len(">"):]
   453  		if !semver.IsValid(v) {
   454  			return badVersion(v)
   455  		}
   456  		if isSemverPrefix(v) {
   457  			// Refuse to say whether >v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3).
   458  			return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query)
   459  		}
   460  		qm.filter = func(mv string) bool { return semver.Compare(mv, v) > 0 }
   461  		qm.preferLower = true
   462  		if !matchesMajor(v) {
   463  			qm.preferIncompatible = true
   464  		}
   465  
   466  	case semver.IsValid(query):
   467  		if isSemverPrefix(query) {
   468  			qm.prefix = query + "."
   469  			// Do not allow the query "v1.2" to match versions lower than "v1.2.0",
   470  			// such as prereleases for that version. (https://golang.org/issue/31972)
   471  			qm.filter = func(mv string) bool { return semver.Compare(mv, query) >= 0 }
   472  		} else {
   473  			qm.canStat = true
   474  			qm.filter = func(mv string) bool { return semver.Compare(mv, query) == 0 }
   475  			qm.prefix = semver.Canonical(query)
   476  		}
   477  		if !matchesMajor(query) {
   478  			qm.preferIncompatible = true
   479  		}
   480  
   481  	default:
   482  		return nil, errRevQuery
   483  	}
   484  
   485  	return qm, nil
   486  }
   487  
   488  // allowsVersion reports whether version v is allowed by the prefix, filter, and
   489  // AllowedFunc of qm.
   490  func (qm *queryMatcher) allowsVersion(ctx context.Context, v string) bool {
   491  	if qm.prefix != "" && !strings.HasPrefix(v, qm.prefix) {
   492  		return false
   493  	}
   494  	if qm.filter != nil && !qm.filter(v) {
   495  		return false
   496  	}
   497  	if qm.allowed != nil {
   498  		if err := qm.allowed(ctx, module.Version{Path: qm.path, Version: v}); errors.Is(err, ErrDisallowed) {
   499  			return false
   500  		}
   501  	}
   502  	return true
   503  }
   504  
   505  // filterVersions classifies versions into releases and pre-releases, filtering
   506  // out:
   507  //  1. versions that do not satisfy the 'allowed' predicate, and
   508  //  2. "+incompatible" versions, if a compatible one satisfies the predicate
   509  //     and the incompatible version is not preferred.
   510  //
   511  // If the allowed predicate returns an error not equivalent to ErrDisallowed,
   512  // filterVersions returns that error.
   513  func (qm *queryMatcher) filterVersions(ctx context.Context, versions []string) (releases, prereleases []string, err error) {
   514  	needIncompatible := qm.preferIncompatible
   515  
   516  	var lastCompatible string
   517  	for _, v := range versions {
   518  		if !qm.allowsVersion(ctx, v) {
   519  			continue
   520  		}
   521  
   522  		if !needIncompatible {
   523  			// We're not yet sure whether we need to include +incomptaible versions.
   524  			// Keep track of the last compatible version we've seen, and use the
   525  			// presence (or absence) of a go.mod file in that version to decide: a
   526  			// go.mod file implies that the module author is supporting modules at a
   527  			// compatible version (and we should ignore +incompatible versions unless
   528  			// requested explicitly), while a lack of go.mod file implies the
   529  			// potential for legacy (pre-modules) versioning without semantic import
   530  			// paths (and thus *with* +incompatible versions).
   531  			//
   532  			// This isn't strictly accurate if the latest compatible version has been
   533  			// replaced by a local file path, because we do not allow file-path
   534  			// replacements without a go.mod file: the user would have needed to add
   535  			// one. However, replacing the last compatible version while
   536  			// simultaneously expecting to upgrade implicitly to a +incompatible
   537  			// version seems like an extreme enough corner case to ignore for now.
   538  
   539  			if !strings.HasSuffix(v, "+incompatible") {
   540  				lastCompatible = v
   541  			} else if lastCompatible != "" {
   542  				// If the latest compatible version is allowed and has a go.mod file,
   543  				// ignore any version with a higher (+incompatible) major version. (See
   544  				// https://golang.org/issue/34165.) Note that we even prefer a
   545  				// compatible pre-release over an incompatible release.
   546  				ok, err := versionHasGoMod(ctx, module.Version{Path: qm.path, Version: lastCompatible})
   547  				if err != nil {
   548  					return nil, nil, err
   549  				}
   550  				if ok {
   551  					// The last compatible version has a go.mod file, so that's the
   552  					// highest version we're willing to consider. Don't bother even
   553  					// looking at higher versions, because they're all +incompatible from
   554  					// here onward.
   555  					break
   556  				}
   557  
   558  				// No acceptable compatible release has a go.mod file, so the versioning
   559  				// for the module might not be module-aware, and we should respect
   560  				// legacy major-version tags.
   561  				needIncompatible = true
   562  			}
   563  		}
   564  
   565  		if semver.Prerelease(v) != "" {
   566  			prereleases = append(prereleases, v)
   567  		} else {
   568  			releases = append(releases, v)
   569  		}
   570  	}
   571  
   572  	return releases, prereleases, nil
   573  }
   574  
   575  type QueryResult struct {
   576  	Mod      module.Version
   577  	Rev      *modfetch.RevInfo
   578  	Packages []string
   579  }
   580  
   581  // QueryPackages is like QueryPattern, but requires that the pattern match at
   582  // least one package and omits the non-package result (if any).
   583  func QueryPackages(ctx context.Context, pattern, query string, current func(string) string, allowed AllowedFunc) ([]QueryResult, error) {
   584  	pkgMods, modOnly, err := QueryPattern(ctx, pattern, query, current, allowed)
   585  
   586  	if len(pkgMods) == 0 && err == nil {
   587  		replacement := Replacement(modOnly.Mod)
   588  		return nil, &PackageNotInModuleError{
   589  			Mod:         modOnly.Mod,
   590  			Replacement: replacement,
   591  			Query:       query,
   592  			Pattern:     pattern,
   593  		}
   594  	}
   595  
   596  	return pkgMods, err
   597  }
   598  
   599  // QueryPattern looks up the module(s) containing at least one package matching
   600  // the given pattern at the given version. The results are sorted by module path
   601  // length in descending order. If any proxy provides a non-empty set of candidate
   602  // modules, no further proxies are tried.
   603  //
   604  // For wildcard patterns, QueryPattern looks in modules with package paths up to
   605  // the first "..." in the pattern. For the pattern "example.com/a/b.../c",
   606  // QueryPattern would consider prefixes of "example.com/a".
   607  //
   608  // If any matching package is in the main module, QueryPattern considers only
   609  // the main module and only the version "latest", without checking for other
   610  // possible modules.
   611  //
   612  // QueryPattern always returns at least one QueryResult (which may be only
   613  // modOnly) or a non-nil error.
   614  func QueryPattern(ctx context.Context, pattern, query string, current func(string) string, allowed AllowedFunc) (pkgMods []QueryResult, modOnly *QueryResult, err error) {
   615  	ctx, span := trace.StartSpan(ctx, "modload.QueryPattern "+pattern+" "+query)
   616  	defer span.Done()
   617  
   618  	base := pattern
   619  
   620  	firstError := func(m *search.Match) error {
   621  		if len(m.Errs) == 0 {
   622  			return nil
   623  		}
   624  		return m.Errs[0]
   625  	}
   626  
   627  	var match func(mod module.Version, roots []string, isLocal bool) *search.Match
   628  	matchPattern := pkgpattern.MatchPattern(pattern)
   629  
   630  	if i := strings.Index(pattern, "..."); i >= 0 {
   631  		base = pathpkg.Dir(pattern[:i+3])
   632  		if base == "." {
   633  			return nil, nil, &WildcardInFirstElementError{Pattern: pattern, Query: query}
   634  		}
   635  		match = func(mod module.Version, roots []string, isLocal bool) *search.Match {
   636  			m := search.NewMatch(pattern)
   637  			matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{mod})
   638  			return m
   639  		}
   640  	} else {
   641  		match = func(mod module.Version, roots []string, isLocal bool) *search.Match {
   642  			m := search.NewMatch(pattern)
   643  			prefix := mod.Path
   644  			if MainModules.Contains(mod.Path) {
   645  				prefix = MainModules.PathPrefix(module.Version{Path: mod.Path})
   646  			}
   647  			for _, root := range roots {
   648  				if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
   649  					m.AddError(err)
   650  				} else if ok {
   651  					m.Pkgs = []string{pattern}
   652  				}
   653  			}
   654  			return m
   655  		}
   656  	}
   657  
   658  	var mainModuleMatches []module.Version
   659  	for _, mainModule := range MainModules.Versions() {
   660  		m := match(mainModule, modRoots, true)
   661  		if len(m.Pkgs) > 0 {
   662  			if query != "upgrade" && query != "patch" {
   663  				return nil, nil, &QueryMatchesPackagesInMainModuleError{
   664  					Pattern:  pattern,
   665  					Query:    query,
   666  					Packages: m.Pkgs,
   667  				}
   668  			}
   669  			if err := allowed(ctx, mainModule); err != nil {
   670  				return nil, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed: %w", pattern, mainModule.Path, err)
   671  			}
   672  			return []QueryResult{{
   673  				Mod:      mainModule,
   674  				Rev:      &modfetch.RevInfo{Version: mainModule.Version},
   675  				Packages: m.Pkgs,
   676  			}}, nil, nil
   677  		}
   678  		if err := firstError(m); err != nil {
   679  			return nil, nil, err
   680  		}
   681  
   682  		var matchesMainModule bool
   683  		if matchPattern(mainModule.Path) {
   684  			mainModuleMatches = append(mainModuleMatches, mainModule)
   685  			matchesMainModule = true
   686  		}
   687  
   688  		if (query == "upgrade" || query == "patch") && matchesMainModule {
   689  			if err := allowed(ctx, mainModule); err == nil {
   690  				modOnly = &QueryResult{
   691  					Mod: mainModule,
   692  					Rev: &modfetch.RevInfo{Version: mainModule.Version},
   693  				}
   694  			}
   695  		}
   696  	}
   697  
   698  	var (
   699  		results          []QueryResult
   700  		candidateModules = modulePrefixesExcludingTarget(base)
   701  	)
   702  	if len(candidateModules) == 0 {
   703  		if modOnly != nil {
   704  			return nil, modOnly, nil
   705  		} else if len(mainModuleMatches) != 0 {
   706  			return nil, nil, &QueryMatchesMainModulesError{
   707  				MainModules: mainModuleMatches,
   708  				Pattern:     pattern,
   709  				Query:       query,
   710  			}
   711  		} else {
   712  			return nil, nil, &PackageNotInModuleError{
   713  				MainModules: mainModuleMatches,
   714  				Query:       query,
   715  				Pattern:     pattern,
   716  			}
   717  		}
   718  	}
   719  
   720  	err = modfetch.TryProxies(func(proxy string) error {
   721  		queryModule := func(ctx context.Context, path string) (r QueryResult, err error) {
   722  			ctx, span := trace.StartSpan(ctx, "modload.QueryPattern.queryModule ["+proxy+"] "+path)
   723  			defer span.Done()
   724  
   725  			pathCurrent := current(path)
   726  			r.Mod.Path = path
   727  			r.Rev, err = queryProxy(ctx, proxy, path, query, pathCurrent, allowed, nil)
   728  			if err != nil {
   729  				return r, err
   730  			}
   731  			r.Mod.Version = r.Rev.Version
   732  			root, isLocal, err := fetch(ctx, r.Mod)
   733  			if err != nil {
   734  				return r, err
   735  			}
   736  			m := match(r.Mod, []string{root}, isLocal)
   737  			r.Packages = m.Pkgs
   738  			if len(r.Packages) == 0 && !matchPattern(path) {
   739  				if err := firstError(m); err != nil {
   740  					return r, err
   741  				}
   742  				replacement := Replacement(r.Mod)
   743  				return r, &PackageNotInModuleError{
   744  					Mod:         r.Mod,
   745  					Replacement: replacement,
   746  					Query:       query,
   747  					Pattern:     pattern,
   748  				}
   749  			}
   750  			return r, nil
   751  		}
   752  
   753  		allResults, err := queryPrefixModules(ctx, candidateModules, queryModule)
   754  		results = allResults[:0]
   755  		for _, r := range allResults {
   756  			if len(r.Packages) == 0 {
   757  				modOnly = &r
   758  			} else {
   759  				results = append(results, r)
   760  			}
   761  		}
   762  		return err
   763  	})
   764  
   765  	if len(mainModuleMatches) > 0 && len(results) == 0 && modOnly == nil && errors.Is(err, fs.ErrNotExist) {
   766  		return nil, nil, &QueryMatchesMainModulesError{
   767  			Pattern: pattern,
   768  			Query:   query,
   769  		}
   770  	}
   771  	return results[:len(results):len(results)], modOnly, err
   772  }
   773  
   774  // modulePrefixesExcludingTarget returns all prefixes of path that may plausibly
   775  // exist as a module, excluding targetPrefix but otherwise including path
   776  // itself, sorted by descending length. Prefixes that are not valid module paths
   777  // but are valid package paths (like "m" or "example.com/.gen") are included,
   778  // since they might be replaced.
   779  func modulePrefixesExcludingTarget(path string) []string {
   780  	prefixes := make([]string, 0, strings.Count(path, "/")+1)
   781  
   782  	mainModulePrefixes := make(map[string]bool)
   783  	for _, m := range MainModules.Versions() {
   784  		mainModulePrefixes[m.Path] = true
   785  	}
   786  
   787  	for {
   788  		if !mainModulePrefixes[path] {
   789  			if _, _, ok := module.SplitPathVersion(path); ok {
   790  				prefixes = append(prefixes, path)
   791  			}
   792  		}
   793  
   794  		j := strings.LastIndexByte(path, '/')
   795  		if j < 0 {
   796  			break
   797  		}
   798  		path = path[:j]
   799  	}
   800  
   801  	return prefixes
   802  }
   803  
   804  func queryPrefixModules(ctx context.Context, candidateModules []string, queryModule func(ctx context.Context, path string) (QueryResult, error)) (found []QueryResult, err error) {
   805  	ctx, span := trace.StartSpan(ctx, "modload.queryPrefixModules")
   806  	defer span.Done()
   807  
   808  	// If the path we're attempting is not in the module cache and we don't have a
   809  	// fetch result cached either, we'll end up making a (potentially slow)
   810  	// request to the proxy or (often even slower) the origin server.
   811  	// To minimize latency, execute all of those requests in parallel.
   812  	type result struct {
   813  		QueryResult
   814  		err error
   815  	}
   816  	results := make([]result, len(candidateModules))
   817  	var wg sync.WaitGroup
   818  	wg.Add(len(candidateModules))
   819  	for i, p := range candidateModules {
   820  		ctx := trace.StartGoroutine(ctx)
   821  		go func(p string, r *result) {
   822  			r.QueryResult, r.err = queryModule(ctx, p)
   823  			wg.Done()
   824  		}(p, &results[i])
   825  	}
   826  	wg.Wait()
   827  
   828  	// Classify the results. In case of failure, identify the error that the user
   829  	// is most likely to find helpful: the most useful class of error at the
   830  	// longest matching path.
   831  	var (
   832  		noPackage   *PackageNotInModuleError
   833  		noVersion   *NoMatchingVersionError
   834  		noPatchBase *NoPatchBaseError
   835  		invalidPath *module.InvalidPathError // see comment in case below
   836  		notExistErr error
   837  	)
   838  	for _, r := range results {
   839  		switch rErr := r.err.(type) {
   840  		case nil:
   841  			found = append(found, r.QueryResult)
   842  		case *PackageNotInModuleError:
   843  			// Given the option, prefer to attribute “package not in module”
   844  			// to modules other than the main one.
   845  			if noPackage == nil || MainModules.Contains(noPackage.Mod.Path) {
   846  				noPackage = rErr
   847  			}
   848  		case *NoMatchingVersionError:
   849  			if noVersion == nil {
   850  				noVersion = rErr
   851  			}
   852  		case *NoPatchBaseError:
   853  			if noPatchBase == nil {
   854  				noPatchBase = rErr
   855  			}
   856  		case *module.InvalidPathError:
   857  			// The prefix was not a valid module path, and there was no replacement.
   858  			// Prefixes like this may appear in candidateModules, since we handle
   859  			// replaced modules that weren't required in the repo lookup process
   860  			// (see lookupRepo).
   861  			//
   862  			// A shorter prefix may be a valid module path and may contain a valid
   863  			// import path, so this is a low-priority error.
   864  			if invalidPath == nil {
   865  				invalidPath = rErr
   866  			}
   867  		default:
   868  			if errors.Is(rErr, fs.ErrNotExist) {
   869  				if notExistErr == nil {
   870  					notExistErr = rErr
   871  				}
   872  			} else if err == nil {
   873  				if len(found) > 0 || noPackage != nil {
   874  					// golang.org/issue/34094: If we have already found a module that
   875  					// could potentially contain the target package, ignore unclassified
   876  					// errors for modules with shorter paths.
   877  
   878  					// golang.org/issue/34383 is a special case of this: if we have
   879  					// already found example.com/foo/v2@v2.0.0 with a matching go.mod
   880  					// file, ignore the error from example.com/foo@v2.0.0.
   881  				} else {
   882  					err = r.err
   883  				}
   884  			}
   885  		}
   886  	}
   887  
   888  	// TODO(#26232): If len(found) == 0 and some of the errors are 4xx HTTP
   889  	// codes, have the auth package recheck the failed paths.
   890  	// If we obtain new credentials for any of them, re-run the above loop.
   891  
   892  	if len(found) == 0 && err == nil {
   893  		switch {
   894  		case noPackage != nil:
   895  			err = noPackage
   896  		case noVersion != nil:
   897  			err = noVersion
   898  		case noPatchBase != nil:
   899  			err = noPatchBase
   900  		case invalidPath != nil:
   901  			err = invalidPath
   902  		case notExistErr != nil:
   903  			err = notExistErr
   904  		default:
   905  			panic("queryPrefixModules: no modules found, but no error detected")
   906  		}
   907  	}
   908  
   909  	return found, err
   910  }
   911  
   912  // A NoMatchingVersionError indicates that Query found a module at the requested
   913  // path, but not at any versions satisfying the query string and allow-function.
   914  //
   915  // NOTE: NoMatchingVersionError MUST NOT implement Is(fs.ErrNotExist).
   916  //
   917  // If the module came from a proxy, that proxy had to return a successful status
   918  // code for the versions it knows about, and thus did not have the opportunity
   919  // to return a non-400 status code to suppress fallback.
   920  type NoMatchingVersionError struct {
   921  	query, current string
   922  }
   923  
   924  func (e *NoMatchingVersionError) Error() string {
   925  	currentSuffix := ""
   926  	if (e.query == "upgrade" || e.query == "patch") && e.current != "" && e.current != "none" {
   927  		currentSuffix = fmt.Sprintf(" (current version is %s)", e.current)
   928  	}
   929  	return fmt.Sprintf("no matching versions for query %q", e.query) + currentSuffix
   930  }
   931  
   932  // A NoPatchBaseError indicates that Query was called with the query "patch"
   933  // but with a current version of "" or "none".
   934  type NoPatchBaseError struct {
   935  	path string
   936  }
   937  
   938  func (e *NoPatchBaseError) Error() string {
   939  	return fmt.Sprintf(`can't query version "patch" of module %s: no existing version is required`, e.path)
   940  }
   941  
   942  // A WildcardInFirstElementError indicates that a pattern passed to QueryPattern
   943  // had a wildcard in its first path element, and therefore had no pattern-prefix
   944  // modules to search in.
   945  type WildcardInFirstElementError struct {
   946  	Pattern string
   947  	Query   string
   948  }
   949  
   950  func (e *WildcardInFirstElementError) Error() string {
   951  	return fmt.Sprintf("no modules to query for %s@%s because first path element contains a wildcard", e.Pattern, e.Query)
   952  }
   953  
   954  // A PackageNotInModuleError indicates that QueryPattern found a candidate
   955  // module at the requested version, but that module did not contain any packages
   956  // matching the requested pattern.
   957  //
   958  // NOTE: PackageNotInModuleError MUST NOT implement Is(fs.ErrNotExist).
   959  //
   960  // If the module came from a proxy, that proxy had to return a successful status
   961  // code for the versions it knows about, and thus did not have the opportunity
   962  // to return a non-400 status code to suppress fallback.
   963  type PackageNotInModuleError struct {
   964  	MainModules []module.Version
   965  	Mod         module.Version
   966  	Replacement module.Version
   967  	Query       string
   968  	Pattern     string
   969  }
   970  
   971  func (e *PackageNotInModuleError) Error() string {
   972  	if len(e.MainModules) > 0 {
   973  		prefix := "workspace modules do"
   974  		if len(e.MainModules) == 1 {
   975  			prefix = fmt.Sprintf("main module (%s) does", e.MainModules[0])
   976  		}
   977  		if strings.Contains(e.Pattern, "...") {
   978  			return fmt.Sprintf("%s not contain packages matching %s", prefix, e.Pattern)
   979  		}
   980  		return fmt.Sprintf("%s not contain package %s", prefix, e.Pattern)
   981  	}
   982  
   983  	found := ""
   984  	if r := e.Replacement; r.Path != "" {
   985  		replacement := r.Path
   986  		if r.Version != "" {
   987  			replacement = fmt.Sprintf("%s@%s", r.Path, r.Version)
   988  		}
   989  		if e.Query == e.Mod.Version {
   990  			found = fmt.Sprintf(" (replaced by %s)", replacement)
   991  		} else {
   992  			found = fmt.Sprintf(" (%s, replaced by %s)", e.Mod.Version, replacement)
   993  		}
   994  	} else if e.Query != e.Mod.Version {
   995  		found = fmt.Sprintf(" (%s)", e.Mod.Version)
   996  	}
   997  
   998  	if strings.Contains(e.Pattern, "...") {
   999  		return fmt.Sprintf("module %s@%s found%s, but does not contain packages matching %s", e.Mod.Path, e.Query, found, e.Pattern)
  1000  	}
  1001  	return fmt.Sprintf("module %s@%s found%s, but does not contain package %s", e.Mod.Path, e.Query, found, e.Pattern)
  1002  }
  1003  
  1004  func (e *PackageNotInModuleError) ImportPath() string {
  1005  	if !strings.Contains(e.Pattern, "...") {
  1006  		return e.Pattern
  1007  	}
  1008  	return ""
  1009  }
  1010  
  1011  // versionHasGoMod returns whether a version has a go.mod file.
  1012  //
  1013  // versionHasGoMod fetches the go.mod file (possibly a fake) and true if it
  1014  // contains anything other than a module directive with the same path. When a
  1015  // module does not have a real go.mod file, the go command acts as if it had one
  1016  // that only contained a module directive. Normal go.mod files created after
  1017  // 1.12 at least have a go directive.
  1018  //
  1019  // This function is a heuristic, since it's possible to commit a file that would
  1020  // pass this test. However, we only need a heurstic for determining whether
  1021  // +incompatible versions may be "latest", which is what this function is used
  1022  // for.
  1023  //
  1024  // This heuristic is useful for two reasons: first, when using a proxy,
  1025  // this lets us fetch from the .mod endpoint which is much faster than the .zip
  1026  // endpoint. The .mod file is used anyway, even if the .zip file contains a
  1027  // go.mod with different content. Second, if we don't fetch the .zip, then
  1028  // we don't need to verify it in go.sum. This makes 'go list -m -u' faster
  1029  // and simpler.
  1030  func versionHasGoMod(_ context.Context, m module.Version) (bool, error) {
  1031  	_, data, err := rawGoModData(m)
  1032  	if err != nil {
  1033  		return false, err
  1034  	}
  1035  	isFake := bytes.Equal(data, modfetch.LegacyGoMod(m.Path))
  1036  	return !isFake, nil
  1037  }
  1038  
  1039  // A versionRepo is a subset of modfetch.Repo that can report information about
  1040  // available versions, but cannot fetch specific source files.
  1041  type versionRepo interface {
  1042  	ModulePath() string
  1043  	CheckReuse(*codehost.Origin) error
  1044  	Versions(prefix string) (*modfetch.Versions, error)
  1045  	Stat(rev string) (*modfetch.RevInfo, error)
  1046  	Latest() (*modfetch.RevInfo, error)
  1047  }
  1048  
  1049  var _ versionRepo = modfetch.Repo(nil)
  1050  
  1051  func lookupRepo(proxy, path string) (repo versionRepo, err error) {
  1052  	err = module.CheckPath(path)
  1053  	if err == nil {
  1054  		repo = modfetch.Lookup(proxy, path)
  1055  	} else {
  1056  		repo = emptyRepo{path: path, err: err}
  1057  	}
  1058  
  1059  	if MainModules == nil {
  1060  		return repo, err
  1061  	} else if _, ok := MainModules.HighestReplaced()[path]; ok {
  1062  		return &replacementRepo{repo: repo}, nil
  1063  	}
  1064  
  1065  	return repo, err
  1066  }
  1067  
  1068  // An emptyRepo is a versionRepo that contains no versions.
  1069  type emptyRepo struct {
  1070  	path string
  1071  	err  error
  1072  }
  1073  
  1074  var _ versionRepo = emptyRepo{}
  1075  
  1076  func (er emptyRepo) ModulePath() string { return er.path }
  1077  func (er emptyRepo) CheckReuse(old *codehost.Origin) error {
  1078  	return fmt.Errorf("empty repo")
  1079  }
  1080  func (er emptyRepo) Versions(prefix string) (*modfetch.Versions, error) {
  1081  	return &modfetch.Versions{}, nil
  1082  }
  1083  func (er emptyRepo) Stat(rev string) (*modfetch.RevInfo, error) { return nil, er.err }
  1084  func (er emptyRepo) Latest() (*modfetch.RevInfo, error)         { return nil, er.err }
  1085  
  1086  // A replacementRepo augments a versionRepo to include the replacement versions
  1087  // (if any) found in the main module's go.mod file.
  1088  //
  1089  // A replacementRepo suppresses "not found" errors for otherwise-nonexistent
  1090  // modules, so a replacementRepo should only be constructed for a module that
  1091  // actually has one or more valid replacements.
  1092  type replacementRepo struct {
  1093  	repo versionRepo
  1094  }
  1095  
  1096  var _ versionRepo = (*replacementRepo)(nil)
  1097  
  1098  func (rr *replacementRepo) ModulePath() string { return rr.repo.ModulePath() }
  1099  
  1100  func (rr *replacementRepo) CheckReuse(old *codehost.Origin) error {
  1101  	return fmt.Errorf("replacement repo")
  1102  }
  1103  
  1104  // Versions returns the versions from rr.repo augmented with any matching
  1105  // replacement versions.
  1106  func (rr *replacementRepo) Versions(prefix string) (*modfetch.Versions, error) {
  1107  	repoVersions, err := rr.repo.Versions(prefix)
  1108  	if err != nil {
  1109  		if !errors.Is(err, os.ErrNotExist) {
  1110  			return nil, err
  1111  		}
  1112  		repoVersions = new(modfetch.Versions)
  1113  	}
  1114  
  1115  	versions := repoVersions.List
  1116  	for _, mm := range MainModules.Versions() {
  1117  		if index := MainModules.Index(mm); index != nil && len(index.replace) > 0 {
  1118  			path := rr.ModulePath()
  1119  			for m := range index.replace {
  1120  				if m.Path == path && strings.HasPrefix(m.Version, prefix) && m.Version != "" && !module.IsPseudoVersion(m.Version) {
  1121  					versions = append(versions, m.Version)
  1122  				}
  1123  			}
  1124  		}
  1125  	}
  1126  
  1127  	if len(versions) == len(repoVersions.List) { // replacement versions added
  1128  		return repoVersions, nil
  1129  	}
  1130  
  1131  	sort.Slice(versions, func(i, j int) bool {
  1132  		return semver.Compare(versions[i], versions[j]) < 0
  1133  	})
  1134  	str.Uniq(&versions)
  1135  	return &modfetch.Versions{List: versions}, nil
  1136  }
  1137  
  1138  func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
  1139  	info, err := rr.repo.Stat(rev)
  1140  	if err == nil {
  1141  		return info, err
  1142  	}
  1143  	var hasReplacements bool
  1144  	for _, v := range MainModules.Versions() {
  1145  		if index := MainModules.Index(v); index != nil && len(index.replace) > 0 {
  1146  			hasReplacements = true
  1147  		}
  1148  	}
  1149  	if !hasReplacements {
  1150  		return info, err
  1151  	}
  1152  
  1153  	v := module.CanonicalVersion(rev)
  1154  	if v != rev {
  1155  		// The replacements in the go.mod file list only canonical semantic versions,
  1156  		// so a non-canonical version can't possibly have a replacement.
  1157  		return info, err
  1158  	}
  1159  
  1160  	path := rr.ModulePath()
  1161  	_, pathMajor, ok := module.SplitPathVersion(path)
  1162  	if ok && pathMajor == "" {
  1163  		if err := module.CheckPathMajor(v, pathMajor); err != nil && semver.Build(v) == "" {
  1164  			v += "+incompatible"
  1165  		}
  1166  	}
  1167  
  1168  	if r := Replacement(module.Version{Path: path, Version: v}); r.Path == "" {
  1169  		return info, err
  1170  	}
  1171  	return rr.replacementStat(v)
  1172  }
  1173  
  1174  func (rr *replacementRepo) Latest() (*modfetch.RevInfo, error) {
  1175  	info, err := rr.repo.Latest()
  1176  	path := rr.ModulePath()
  1177  
  1178  	if v, ok := MainModules.HighestReplaced()[path]; ok {
  1179  		if v == "" {
  1180  			// The only replacement is a wildcard that doesn't specify a version, so
  1181  			// synthesize a pseudo-version with an appropriate major version and a
  1182  			// timestamp below any real timestamp. That way, if the main module is
  1183  			// used from within some other module, the user will be able to upgrade
  1184  			// the requirement to any real version they choose.
  1185  			if _, pathMajor, ok := module.SplitPathVersion(path); ok && len(pathMajor) > 0 {
  1186  				v = module.PseudoVersion(pathMajor[1:], "", time.Time{}, "000000000000")
  1187  			} else {
  1188  				v = module.PseudoVersion("v0", "", time.Time{}, "000000000000")
  1189  			}
  1190  		}
  1191  
  1192  		if err != nil || semver.Compare(v, info.Version) > 0 {
  1193  			return rr.replacementStat(v)
  1194  		}
  1195  	}
  1196  
  1197  	return info, err
  1198  }
  1199  
  1200  func (rr *replacementRepo) replacementStat(v string) (*modfetch.RevInfo, error) {
  1201  	rev := &modfetch.RevInfo{Version: v}
  1202  	if module.IsPseudoVersion(v) {
  1203  		rev.Time, _ = module.PseudoVersionTime(v)
  1204  		rev.Short, _ = module.PseudoVersionRev(v)
  1205  	}
  1206  	return rev, nil
  1207  }
  1208  
  1209  // A QueryMatchesMainModulesError indicates that a query requests
  1210  // a version of the main module that cannot be satisfied.
  1211  // (The main module's version cannot be changed.)
  1212  type QueryMatchesMainModulesError struct {
  1213  	MainModules []module.Version
  1214  	Pattern     string
  1215  	Query       string
  1216  }
  1217  
  1218  func (e *QueryMatchesMainModulesError) Error() string {
  1219  	if MainModules.Contains(e.Pattern) {
  1220  		return fmt.Sprintf("can't request version %q of the main module (%s)", e.Query, e.Pattern)
  1221  	}
  1222  
  1223  	plural := ""
  1224  	mainModulePaths := make([]string, len(e.MainModules))
  1225  	for i := range e.MainModules {
  1226  		mainModulePaths[i] = e.MainModules[i].Path
  1227  	}
  1228  	if len(e.MainModules) > 1 {
  1229  		plural = "s"
  1230  	}
  1231  	return fmt.Sprintf("can't request version %q of pattern %q that includes the main module%s (%s)", e.Query, e.Pattern, plural, strings.Join(mainModulePaths, ", "))
  1232  }
  1233  
  1234  // A QueryUpgradesAllError indicates that a query requests
  1235  // an upgrade on the all pattern.
  1236  // (The main module's version cannot be changed.)
  1237  type QueryUpgradesAllError struct {
  1238  	MainModules []module.Version
  1239  	Query       string
  1240  }
  1241  
  1242  func (e *QueryUpgradesAllError) Error() string {
  1243  	var plural string = ""
  1244  	if len(e.MainModules) != 1 {
  1245  		plural = "s"
  1246  	}
  1247  
  1248  	return fmt.Sprintf("can't request version %q of pattern \"all\" that includes the main module%s", e.Query, plural)
  1249  }
  1250  
  1251  // A QueryMatchesPackagesInMainModuleError indicates that a query cannot be
  1252  // satisfied because it matches one or more packages found in the main module.
  1253  type QueryMatchesPackagesInMainModuleError struct {
  1254  	Pattern  string
  1255  	Query    string
  1256  	Packages []string
  1257  }
  1258  
  1259  func (e *QueryMatchesPackagesInMainModuleError) Error() string {
  1260  	if len(e.Packages) > 1 {
  1261  		return fmt.Sprintf("pattern %s matches %d packages in the main module, so can't request version %s", e.Pattern, len(e.Packages), e.Query)
  1262  	}
  1263  
  1264  	if search.IsMetaPackage(e.Pattern) || strings.Contains(e.Pattern, "...") {
  1265  		return fmt.Sprintf("pattern %s matches package %s in the main module, so can't request version %s", e.Pattern, e.Packages[0], e.Query)
  1266  	}
  1267  
  1268  	return fmt.Sprintf("package %s is in the main module, so can't request version %s", e.Packages[0], e.Query)
  1269  }