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