// Query looks up a revision of a given module given a version query string. // The module must be a complete module path. // The version must take one of the following forms: // // - the literal string "latest", denoting the latest available, allowed // tagged version, with non-prereleases preferred over prereleases. // If there are no tagged versions in the repo, latest returns the most // recent commit. // // - the literal string "upgrade", equivalent to "latest" except that if // current is a newer version, current will be returned (see below). // // - the literal string "patch", denoting the latest available tagged version // with the same major and minor number as current (see below). // // - v1, denoting the latest available tagged version v1.x.x. // // - v1.2, denoting the latest available tagged version v1.2.x. // // - v1.2.3, a semantic version string denoting that tagged version. // // - <v1.2.3, <=v1.2.3, >v1.2.3, >=v1.2.3, // denoting the version closest to the target and satisfying the given operator, // with non-prereleases preferred over prereleases. // // - a repository commit identifier or tag, denoting that commit. // // current denotes the currently-selected version of the module; it may be // "none" if no version is currently selected, or "" if the currently-selected // version is unknown or should not be considered. If query is // "upgrade" or "patch", current will be returned if it is a newer // semantic version or a chronologically later pseudo-version than the // version that would otherwise be chosen. This prevents accidental downgrades // from newer pre-release or development versions. // // The allowed function (which may be nil) is used to filter out unsuitable // versions (see AllowedFunc documentation for details). If the query refers to // a specific revision (for example, "master"; see IsRevisionQuery), and the // revision is disallowed by allowed, Query returns the error. If the query // does not refer to a specific revision (for example, "latest"), Query // acts as if versions disallowed by allowed do not exist. // // If path is the path of the main module and the query is "latest", // Query returns Target.Version as the version. // // Query often returns a non-nil *RevInfo with a non-nil error, // to provide an info.Origin that can allow the error to be cached. func Query(ctx context.Context, path, query, current string, allowed AllowedFunc) (*modfetch.RevInfo, error) { … } // queryReuse is like Query but also takes a map of module info that can be reused // if the validation criteria in Origin are met. func queryReuse(ctx context.Context, path, query, current string, allowed AllowedFunc, reuse map[module.Version]*modinfo.ModulePublic) (*modfetch.RevInfo, error) { … } // checkReuse checks whether a revision of a given module // for a given module may be reused, according to the information in origin. func checkReuse(ctx context.Context, m module.Version, old *codehost.Origin) error { … } func checkReuseRepo(ctx context.Context, repo versionRepo, path, query string, origin *codehost.Origin) error { … } type AllowedFunc … var errQueryDisabled … type queryDisabledError … func (queryDisabledError) Error() string { … } func queryProxy(ctx context.Context, proxy, path, query, current string, allowed AllowedFunc, reuse map[module.Version]*modinfo.ModulePublic) (*modfetch.RevInfo, error) { … } // IsRevisionQuery returns true if vers is a version query that may refer to // a particular version or revision in a repository like "v1.0.0", "master", // or "0123abcd". IsRevisionQuery returns false if vers is a query that // chooses from among available versions like "latest" or ">v1.0.0". func IsRevisionQuery(path, vers string) bool { … } type queryMatcher … var errRevQuery … // newQueryMatcher returns a new queryMatcher that matches the versions // specified by the given query on the module with the given path. // // If the query can only be resolved by statting a non-SemVer revision, // newQueryMatcher returns errRevQuery. func newQueryMatcher(path string, query, current string, allowed AllowedFunc) (*queryMatcher, error) { … } // allowsVersion reports whether version v is allowed by the prefix, filter, and // AllowedFunc of qm. func (qm *queryMatcher) allowsVersion(ctx context.Context, v string) bool { … } // filterVersions classifies versions into releases and pre-releases, filtering // out: // 1. versions that do not satisfy the 'allowed' predicate, and // 2. "+incompatible" versions, if a compatible one satisfies the predicate // and the incompatible version is not preferred. // // If the allowed predicate returns an error not equivalent to ErrDisallowed, // filterVersions returns that error. func (qm *queryMatcher) filterVersions(ctx context.Context, versions []string) (releases, prereleases []string, err error) { … } type QueryResult … // QueryPackages is like QueryPattern, but requires that the pattern match at // least one package and omits the non-package result (if any). func QueryPackages(ctx context.Context, pattern, query string, current func(string) string, allowed AllowedFunc) ([]QueryResult, error) { … } // QueryPattern looks up the module(s) containing at least one package matching // the given pattern at the given version. The results are sorted by module path // length in descending order. If any proxy provides a non-empty set of candidate // modules, no further proxies are tried. // // For wildcard patterns, QueryPattern looks in modules with package paths up to // the first "..." in the pattern. For the pattern "example.com/a/b.../c", // QueryPattern would consider prefixes of "example.com/a". // // If any matching package is in the main module, QueryPattern considers only // the main module and only the version "latest", without checking for other // possible modules. // // QueryPattern always returns at least one QueryResult (which may be only // modOnly) or a non-nil error. func QueryPattern(ctx context.Context, pattern, query string, current func(string) string, allowed AllowedFunc) (pkgMods []QueryResult, modOnly *QueryResult, err error) { … } // modulePrefixesExcludingTarget returns all prefixes of path that may plausibly // exist as a module, excluding targetPrefix but otherwise including path // itself, sorted by descending length. Prefixes that are not valid module paths // but are valid package paths (like "m" or "example.com/.gen") are included, // since they might be replaced. func modulePrefixesExcludingTarget(path string) []string { … } func queryPrefixModules(ctx context.Context, candidateModules []string, queryModule func(ctx context.Context, path string) (QueryResult, error)) (found []QueryResult, err error) { … } type NoMatchingVersionError … func (e *NoMatchingVersionError) Error() string { … } type NoPatchBaseError … func (e *NoPatchBaseError) Error() string { … } type WildcardInFirstElementError … func (e *WildcardInFirstElementError) Error() string { … } type PackageNotInModuleError … func (e *PackageNotInModuleError) Error() string { … } func (e *PackageNotInModuleError) ImportPath() string { … } // versionHasGoMod returns whether a version has a go.mod file. // // versionHasGoMod fetches the go.mod file (possibly a fake) and true if it // contains anything other than a module directive with the same path. When a // module does not have a real go.mod file, the go command acts as if it had one // that only contained a module directive. Normal go.mod files created after // 1.12 at least have a go directive. // // This function is a heuristic, since it's possible to commit a file that would // pass this test. However, we only need a heuristic for determining whether // +incompatible versions may be "latest", which is what this function is used // for. // // This heuristic is useful for two reasons: first, when using a proxy, // this lets us fetch from the .mod endpoint which is much faster than the .zip // endpoint. The .mod file is used anyway, even if the .zip file contains a // go.mod with different content. Second, if we don't fetch the .zip, then // we don't need to verify it in go.sum. This makes 'go list -m -u' faster // and simpler. func versionHasGoMod(_ context.Context, m module.Version) (bool, error) { … } type versionRepo … var _ … func lookupRepo(ctx context.Context, proxy, path string) (repo versionRepo, err error) { … } type emptyRepo … var _ … func (er emptyRepo) ModulePath() string { … } func (er emptyRepo) CheckReuse(ctx context.Context, old *codehost.Origin) error { … } func (er emptyRepo) Versions(ctx context.Context, prefix string) (*modfetch.Versions, error) { … } func (er emptyRepo) Stat(ctx context.Context, rev string) (*modfetch.RevInfo, error) { … } func (er emptyRepo) Latest(ctx context.Context) (*modfetch.RevInfo, error) { … } type replacementRepo … var _ … func (rr *replacementRepo) ModulePath() string { … } func (rr *replacementRepo) CheckReuse(ctx context.Context, old *codehost.Origin) error { … } // Versions returns the versions from rr.repo augmented with any matching // replacement versions. func (rr *replacementRepo) Versions(ctx context.Context, prefix string) (*modfetch.Versions, error) { … } func (rr *replacementRepo) Stat(ctx context.Context, rev string) (*modfetch.RevInfo, error) { … } func (rr *replacementRepo) Latest(ctx context.Context) (*modfetch.RevInfo, error) { … } func (rr *replacementRepo) replacementStat(v string) (*modfetch.RevInfo, error) { … } type QueryMatchesMainModulesError … func (e *QueryMatchesMainModulesError) Error() string { … } type QueryUpgradesAllError … func (e *QueryUpgradesAllError) Error() string { … } type QueryMatchesPackagesInMainModuleError … func (e *QueryMatchesPackagesInMainModuleError) Error() string { … }