Copyright 2021 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package fetch

import (
	
	
	

	
	
	
	
	
	
)
LatestModuleVersions uses the proxy to get information about the latest versions of modulePath. It returns a LatestModuleVersions whose RawVersion and CookedVersion is obtained from the proxy @v/list and @latest endpoints. The cooked version is computed by choosing the latest version after removing versions that are retracted in the go.mod file of the raw version. The GoodVersion of LatestModuleVersions is not set. It should be determined when inserting into a data source, since it depends on the contents of the data source. The hasGoMod function that is passed in should check if version v of the module has a go.mod file, using a source other than the proxy (e.g. a database). If it doesn't have enough information to decide, it should return an error that wraps derrors.NotFound. If a module has no tagged versions and hasn't been accessed at a pseudo-version in a while, then the proxy's list endpoint will serve nothing and its @latest endpoint will return a 404/410. (Example: cloud.google.com/go/compute/metadata, which has a v0.0.0-20181107005212-dafb9c8d8707 that @latest does not return.) That is not a failure, but a valid state in which there is no version information for a module, even though particular pseudo-versions of the module might exist. In this case, LatestModuleVersions returns (nil, nil). As a special case, the "std" module's versions are fetched from the repo (by calling stdlib.Versions). We assume stdlib versions are never retracted, and that there are no incompatible versions.
func ( context.Context,  string,  *proxy.Client,  func( string) (bool, error)) ( *internal.LatestModuleVersions,  error) {
	defer derrors.WrapStack(&, "LatestModuleVersions(%q)", )

	defer func() {
		if  != nil {
			log.Debugf(, "LatestModuleVersions(%q) => (raw=%q cooked=%q, %v)", , .RawVersion, .CookedVersion, )
		}
	}()

	if  == stdlib.ModulePath {
		,  := stdlib.Versions()
		if  != nil {
			return nil, 
		}
		 := version.LatestOf()
		if  == "" {
			return nil, errors.New("no versions for stdlib")
		}
		return internal.NewLatestModuleVersions(, , , "", []byte("module std"))
	}
Remember calls to hasGoMod because they can be expensive.
	 := map[string]bool{}
	 := func( string) (bool, error) {
		,  := []
		if  {
			return , nil
		}
		 := derrors.NotFound
		if  != nil {
			,  = ()
		}
		if  != nil && !errors.Is(, derrors.NotFound) {
			return false, 
		}
hasGoMod doesn't know; download the zip.
			,  := .Zip(, , )
			if  != nil {
				return false, 
			}
			 = hasGoModFile(, , )
		}
		[] = 
		return , nil
	}
Get the raw latest version.
	,  := .Versions(, )
	if  != nil {
		return nil, 
	}
	,  := .Info(, , internal.LatestVersion)
No information from the proxy, but not a showstopper either; we can proceed with the result of the list endpoint.
	} else if  != nil {
		return nil, 
	} else {
		 = append(, .Version)
	}
No tagged versions, and nothing from @latest: no version information.
		return nil, nil
	}
	,  := version.Latest(, )
	if  != nil {
		return nil, 
	}
Get the go.mod file at the raw latest version.
	,  := .Mod(, , )
Something's wrong with the go.mod file, so assume a minimal one instead of failing.
		log.Warningf(, "proxy.Mod(%q, %q): %v; using minimal go.mod for latest version info",
			, )
		 = []byte(fmt.Sprintf("module %s", ))
	}
	,  := internal.NewLatestModuleVersions(, , "", "", )
An error here means a bad go.mod file.
		return nil, fmt.Errorf("%v: %w", , derrors.BadModule)
	}
Get the cooked latest version by disallowing retracted versions.
	 := version.RemoveIf(, .IsRetracted)
	if len() == len() {
		.CookedVersion = .RawVersion
	} else {
		.CookedVersion,  = version.Latest(, )
		if  != nil {
			return nil, 
		}
	}
	return , nil