internal/datasource: factor out everything else

Move GetLatestInfo to the shared datasource.

Remove GetModuleInfo; it was unused.

For golang/go#47780

Change-Id: I94419458f219759f83c990124d31fcfbddbb4b8e
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/344951
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/internal/datasource/datasource.go b/internal/datasource/datasource.go
index 25181ca..34e684a 100644
--- a/internal/datasource/datasource.go
+++ b/internal/datasource/datasource.go
@@ -11,16 +11,19 @@
 	"context"
 	"errors"
 	"fmt"
+	"strconv"
 	"strings"
 	"time"
 
 	lru "github.com/hashicorp/golang-lru"
+	"golang.org/x/mod/semver"
 	"golang.org/x/pkgsite/internal"
 	"golang.org/x/pkgsite/internal/derrors"
 	"golang.org/x/pkgsite/internal/fetch"
 	"golang.org/x/pkgsite/internal/log"
 	"golang.org/x/pkgsite/internal/proxy"
 	"golang.org/x/pkgsite/internal/source"
+	"golang.org/x/pkgsite/internal/version"
 )
 
 // dataSource implements the internal.DataSource interface, by trying a list of
@@ -201,3 +204,74 @@
 	}
 	return nil
 }
+
+// GetLatestInfo returns latest information for unitPath and modulePath.
+func (ds *dataSource) GetLatestInfo(ctx context.Context, unitPath, modulePath string, latestUnitMeta *internal.UnitMeta) (latest internal.LatestInfo, err error) {
+	defer derrors.Wrap(&err, "GetLatestInfo(ctx, %q, %q)", unitPath, modulePath)
+
+	if ds.prox == nil {
+		return internal.LatestInfo{}, nil
+	}
+
+	if latestUnitMeta == nil {
+		latestUnitMeta, err = ds.GetUnitMeta(ctx, unitPath, internal.UnknownModulePath, version.Latest)
+		if err != nil {
+			return latest, err
+		}
+	}
+	latest.MinorVersion = latestUnitMeta.Version
+	latest.MinorModulePath = latestUnitMeta.ModulePath
+
+	latest.MajorModulePath, latest.MajorUnitPath, err = ds.getLatestMajorVersion(ctx, unitPath, modulePath)
+	if err != nil {
+		return latest, err
+	}
+	// Do not try to discover whether the unit is in the latest minor version; assume it is.
+	latest.UnitExistsAtMinor = true
+	return latest, nil
+}
+
+// getLatestMajorVersion returns the latest module path and the full package path
+// of the latest version found in the proxy by iterating through vN versions.
+// This function does not attempt to find whether the full path exists
+// in the new major version.
+func (ds *dataSource) getLatestMajorVersion(ctx context.Context, fullPath, modulePath string) (_ string, _ string, err error) {
+	// We are checking if the full path is valid so that we can forward the error if not.
+	seriesPath := internal.SeriesPathForModule(modulePath)
+	info, err := ds.prox.Info(ctx, seriesPath, version.Latest)
+	if err != nil {
+		return "", "", err
+	}
+
+	// Converting version numbers to integers may cause an overflow, as version
+	// numbers need not fit into machine integers.
+	// While using Atoi is wrong, for it to fail, the version number must reach a
+	// value higher than at least 2^31, which is unlikely.
+	startVersion, err := strconv.Atoi(strings.TrimPrefix(semver.Major(info.Version), "v"))
+	if err != nil {
+		return "", "", err
+	}
+	startVersion++
+
+	// We start checking versions from "/v2" or higher, since v1 and v0 versions
+	// don't have a major version at the end of the modulepath.
+	if startVersion < 2 {
+		startVersion = 2
+	}
+
+	for v := startVersion; ; v++ {
+		query := fmt.Sprintf("%s/v%d", seriesPath, v)
+
+		_, err := ds.prox.Info(ctx, query, version.Latest)
+		if errors.Is(err, derrors.NotFound) {
+			if v == 2 {
+				return modulePath, fullPath, nil
+			}
+			latestModulePath := fmt.Sprintf("%s/v%d", seriesPath, v-1)
+			return latestModulePath, latestModulePath, nil
+		}
+		if err != nil {
+			return "", "", err
+		}
+	}
+}
diff --git a/internal/datasource/local.go b/internal/datasource/local.go
index 2315d33..feffa36 100644
--- a/internal/datasource/local.go
+++ b/internal/datasource/local.go
@@ -71,7 +71,7 @@
 
 // GetLatestInfo is not implemented.
 func (ds *LocalDataSource) GetLatestInfo(ctx context.Context, unitPath, modulePath string, latestUnitMeta *internal.UnitMeta) (internal.LatestInfo, error) {
-	return internal.LatestInfo{}, nil
+	return ds.ds.GetLatestInfo(ctx, unitPath, modulePath, latestUnitMeta)
 }
 
 // GetNestedModules is not implemented.
diff --git a/internal/datasource/proxy.go b/internal/datasource/proxy.go
index f3d08dc..bafd6d5 100644
--- a/internal/datasource/proxy.go
+++ b/internal/datasource/proxy.go
@@ -6,19 +6,12 @@
 
 import (
 	"context"
-	"errors"
-	"fmt"
-	"strconv"
-	"strings"
 	"time"
 
-	"golang.org/x/mod/semver"
 	"golang.org/x/pkgsite/internal"
-	"golang.org/x/pkgsite/internal/derrors"
 	"golang.org/x/pkgsite/internal/fetch"
 	"golang.org/x/pkgsite/internal/proxy"
 	"golang.org/x/pkgsite/internal/source"
-	"golang.org/x/pkgsite/internal/version"
 )
 
 var _ internal.DataSource = (*ProxyDataSource)(nil)
@@ -54,67 +47,5 @@
 
 // GetLatestInfo returns latest information for unitPath and modulePath.
 func (ds *ProxyDataSource) GetLatestInfo(ctx context.Context, unitPath, modulePath string, latestUnitMeta *internal.UnitMeta) (latest internal.LatestInfo, err error) {
-	defer derrors.Wrap(&err, "GetLatestInfo(ctx, %q, %q)", unitPath, modulePath)
-
-	if latestUnitMeta == nil {
-		latestUnitMeta, err = ds.GetUnitMeta(ctx, unitPath, internal.UnknownModulePath, version.Latest)
-		if err != nil {
-			return latest, err
-		}
-	}
-	latest.MinorVersion = latestUnitMeta.Version
-	latest.MinorModulePath = latestUnitMeta.ModulePath
-
-	latest.MajorModulePath, latest.MajorUnitPath, err = ds.getLatestMajorVersion(ctx, unitPath, modulePath)
-	if err != nil {
-		return latest, err
-	}
-	// Do not try to discover whether the unit is in the latest minor version; assume it is.
-	latest.UnitExistsAtMinor = true
-	return latest, nil
-}
-
-// getLatestMajorVersion returns the latest module path and the full package path
-// of the latest version found in the proxy by iterating through vN versions.
-// This function does not attempt to find whether the full path exists
-// in the new major version.
-func (ds *ProxyDataSource) getLatestMajorVersion(ctx context.Context, fullPath, modulePath string) (_ string, _ string, err error) {
-	// We are checking if the full path is valid so that we can forward the error if not.
-	seriesPath := internal.SeriesPathForModule(modulePath)
-	info, err := ds.ds.prox.Info(ctx, seriesPath, version.Latest)
-	if err != nil {
-		return "", "", err
-	}
-
-	// Converting version numbers to integers may cause an overflow, as version
-	// numbers need not fit into machine integers.
-	// While using Atoi is wrong, for it to fail, the version number must reach a
-	// value higher than at least 2^31, which is unlikely.
-	startVersion, err := strconv.Atoi(strings.TrimPrefix(semver.Major(info.Version), "v"))
-	if err != nil {
-		return "", "", err
-	}
-	startVersion++
-
-	// We start checking versions from "/v2" or higher, since v1 and v0 versions
-	// don't have a major version at the end of the modulepath.
-	if startVersion < 2 {
-		startVersion = 2
-	}
-
-	for v := startVersion; ; v++ {
-		query := fmt.Sprintf("%s/v%d", seriesPath, v)
-
-		_, err := ds.ds.prox.Info(ctx, query, version.Latest)
-		if errors.Is(err, derrors.NotFound) {
-			if v == 2 {
-				return modulePath, fullPath, nil
-			}
-			latestModulePath := fmt.Sprintf("%s/v%d", seriesPath, v-1)
-			return latestModulePath, latestModulePath, nil
-		}
-		if err != nil {
-			return "", "", err
-		}
-	}
+	return ds.ds.GetLatestInfo(ctx, unitPath, modulePath, latestUnitMeta)
 }
diff --git a/internal/datasource/proxy_details.go b/internal/datasource/proxy_details.go
index 3d01727..77f29fa 100644
--- a/internal/datasource/proxy_details.go
+++ b/internal/datasource/proxy_details.go
@@ -17,17 +17,6 @@
 	return ds.ds.GetUnit(ctx, um, field, bc)
 }
 
-// GetModuleInfo returns the ModuleInfo as fetched from the proxy for module
-// version specified by modulePath and version.
-func (ds *ProxyDataSource) GetModuleInfo(ctx context.Context, modulePath, version string) (_ *internal.ModuleInfo, err error) {
-	defer derrors.Wrap(&err, "GetModuleInfo(%q, %q)", modulePath, version)
-	m, err := ds.ds.getModule(ctx, modulePath, version)
-	if err != nil {
-		return nil, err
-	}
-	return &m.ModuleInfo, nil
-}
-
 func (ds *ProxyDataSource) GetUnitMeta(ctx context.Context, path, requestedModulePath, requestedVersion string) (_ *internal.UnitMeta, err error) {
 	return ds.ds.GetUnitMeta(ctx, path, requestedModulePath, requestedVersion)
 }
diff --git a/internal/datasource/proxy_test.go b/internal/datasource/proxy_test.go
index 4fcd767..9730c66 100644
--- a/internal/datasource/proxy_test.go
+++ b/internal/datasource/proxy_test.go
@@ -66,64 +66,8 @@
 			GOARCH:   "amd64",
 		}},
 	}
-	cmpOpts = append([]cmp.Option{
-		cmpopts.IgnoreFields(licenses.License{}, "Contents"),
-		cmpopts.IgnoreFields(internal.ModuleInfo{}, "SourceInfo"),
-	}, sample.LicenseCmpOpts...)
 )
 
-func TestGetModuleInfo(t *testing.T) {
-	ctx, ds, teardown := setup(t, false)
-	defer teardown()
-
-	modinfo := func(m, v string) *internal.ModuleInfo {
-		t.Helper()
-		mi, err := ds.GetModuleInfo(ctx, m, v)
-		if err != nil {
-			t.Fatal(err)
-		}
-		return mi
-	}
-
-	wantModuleInfo := internal.ModuleInfo{
-		ModulePath:        "example.com/basic",
-		Version:           "v1.1.0",
-		CommitTime:        time.Date(2019, 1, 30, 0, 0, 0, 0, time.UTC),
-		IsRedistributable: true,
-		HasGoMod:          true,
-	}
-	got := modinfo("example.com/basic", "v1.1.0")
-	if diff := cmp.Diff(&wantModuleInfo, got, cmpOpts...); diff != "" {
-		t.Errorf("GetModuleInfo diff (-want +got):\n%s", diff)
-	}
-
-	// Get v1.0.0 of a deprecated module. The deprecation comment is in
-	// the latest version, v1.1.0.
-	got = modinfo("example.com/deprecated", "v1.0.0")
-	if !got.Deprecated {
-		t.Fatal("got not deprecated, want deprecated")
-	}
-	if want := "use something else"; got.DeprecationComment != want {
-		t.Errorf("got %q, want %q", got.DeprecationComment, want)
-	}
-
-	// Get v1.0.0 of a module with retractions. It should not be marked
-	// retracted, even though its own go.mod says it should be, because
-	// the latest go.mod does not retract it.
-	if modinfo("example.com/retractions", "v1.0.0").Retracted {
-		t.Fatal("got retracted, wanted false")
-	}
-	// v1.1.0 of the module is retracted.
-	got = modinfo("example.com/retractions", "v1.1.0")
-	if !got.Retracted {
-		t.Fatal("got retracted false, wanted true")
-	}
-	if want := "worse"; got.RetractionRationale != want {
-		t.Errorf("got rationale %q, want %q", got.RetractionRationale, want)
-	}
-
-}
-
 func TestProxyGetUnitMeta(t *testing.T) {
 	ctx, ds, teardown := setup(t, false)
 	defer teardown()