internal/fetch: move all getters to a single source file

Pure code motion.

For golang/go#47834

Change-Id: Ieef2491431fa37b68a184eb9e8e309d3437a8f48
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/343953
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/fetch/fetch.go b/internal/fetch/fetch.go
index e7847eb..c9fe09b 100644
--- a/internal/fetch/fetch.go
+++ b/internal/fetch/fetch.go
@@ -90,20 +90,6 @@
 	}
 )
 
-// ModuleGetter gets module data.
-type ModuleGetter interface {
-	// Info returns basic information about the module.
-	Info(ctx context.Context, path, version string) (*proxy.VersionInfo, error)
-	// Mod returns the contents of the module's go.mod file.
-	Mod(ctx context.Context, path, version string) ([]byte, error)
-	// FS returns an FS for the module's contents. The FS should match the format
-	// of a module zip file.
-	FS(ctx context.Context, path, version string) (fs.FS, error)
-	// ZipSize returns the approximate size of the zip file in bytes.
-	// It is used only for load-shedding.
-	ZipSize(ctx context.Context, path, version string) (int64, error)
-}
-
 type FetchResult struct {
 	ModulePath       string
 	RequestedVersion string
diff --git a/internal/fetch/fetchlocal.go b/internal/fetch/fetchlocal.go
deleted file mode 100644
index b7ffcbd..0000000
--- a/internal/fetch/fetchlocal.go
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2020 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 (
-	"archive/zip"
-	"bytes"
-	"context"
-	"errors"
-	"fmt"
-	"io"
-	"io/fs"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"strings"
-	"time"
-
-	"golang.org/x/mod/modfile"
-	"golang.org/x/pkgsite/internal/derrors"
-	"golang.org/x/pkgsite/internal/proxy"
-)
-
-// Version and commit time are pre specified when fetching a local module, as these
-// fields are normally obtained from a proxy.
-var (
-	LocalVersion    = "v0.0.0"
-	LocalCommitTime = time.Time{}
-)
-
-// A directoryModuleGetter is a ModuleGetter whose source is a directory in the file system that contains
-// a module's files.
-type directoryModuleGetter struct {
-	modulePath string
-	dir        string
-}
-
-// NewDirectoryModuleGetter returns a ModuleGetter for reading a module from a directory.
-func NewDirectoryModuleGetter(modulePath, dir string) (*directoryModuleGetter, error) {
-	if modulePath == "" {
-		goModBytes, err := ioutil.ReadFile(filepath.Join(dir, "go.mod"))
-		if err != nil {
-			return nil, fmt.Errorf("cannot obtain module path for %q (%v): %w", dir, err, derrors.BadModule)
-		}
-		modulePath = modfile.ModulePath(goModBytes)
-		if modulePath == "" {
-			return nil, fmt.Errorf("go.mod in %q has no module path: %w", dir, derrors.BadModule)
-		}
-	}
-	return &directoryModuleGetter{
-		dir:        dir,
-		modulePath: modulePath,
-	}, nil
-}
-
-func (g *directoryModuleGetter) checkPath(path string) error {
-	if path != g.modulePath {
-		return fmt.Errorf("given module path %q does not match %q for directory %q: %w",
-			path, g.modulePath, g.dir, derrors.NotFound)
-	}
-	return nil
-}
-
-// Info returns basic information about the module.
-func (g *directoryModuleGetter) Info(ctx context.Context, path, version string) (*proxy.VersionInfo, error) {
-	if err := g.checkPath(path); err != nil {
-		return nil, err
-	}
-	return &proxy.VersionInfo{
-		Version: LocalVersion,
-		Time:    LocalCommitTime,
-	}, nil
-}
-
-// Mod returns the contents of the module's go.mod file.
-// If the file does not exist, it returns a synthesized one.
-func (g *directoryModuleGetter) Mod(ctx context.Context, path, version string) ([]byte, error) {
-	if err := g.checkPath(path); err != nil {
-		return nil, err
-	}
-	data, err := ioutil.ReadFile(filepath.Join(g.dir, "go.mod"))
-	if errors.Is(err, os.ErrNotExist) {
-		return []byte(fmt.Sprintf("module %s\n", g.modulePath)), nil
-	}
-	return data, err
-}
-
-// FS returns an fs.FS for the module.
-func (g *directoryModuleGetter) FS(ctx context.Context, path, version string) (fs.FS, error) {
-	if err := g.checkPath(path); err != nil {
-		return nil, err
-	}
-	return createZipReader(g.dir, path, LocalVersion)
-}
-
-// ZipSize returns the approximate size of the zip file in bytes.
-func (g *directoryModuleGetter) ZipSize(ctx context.Context, path, version string) (int64, error) {
-	return 0, errors.New("directoryModuleGetter.ZipSize unimplemented")
-}
-
-// createZipReader creates a zip file from a directory given a local path and
-// returns a zip.Reader to be passed to processZipFile. The purpose of the
-// function is to transform a local go module into a zip file to be processed by
-// existing functions.
-func createZipReader(localPath, modulePath, version string) (*zip.Reader, error) {
-	buf := new(bytes.Buffer)
-	w := zip.NewWriter(buf)
-	err := filepath.Walk(localPath, func(path string, info os.FileInfo, err error) error {
-		if err != nil {
-			return err
-		}
-		if info.IsDir() {
-			return nil
-		}
-
-		readFrom, err := os.Open(path)
-		if err != nil {
-			return err
-		}
-		defer readFrom.Close()
-
-		writeTo, err := w.Create(filepath.Join(moduleVersionDir(modulePath, version), strings.TrimPrefix(path, localPath)))
-		if err != nil {
-			return err
-		}
-
-		_, err = io.Copy(writeTo, readFrom)
-		return err
-	})
-	if err != nil {
-		return nil, err
-	}
-	if err := w.Close(); err != nil {
-		return nil, err
-	}
-
-	reader := bytes.NewReader(buf.Bytes())
-	return zip.NewReader(reader, reader.Size())
-}
diff --git a/internal/fetch/fs.go b/internal/fetch/fs.go
deleted file mode 100644
index 6a78897..0000000
--- a/internal/fetch/fs.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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 (
-	"archive/zip"
-	"bytes"
-	"context"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io/fs"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-
-	"golang.org/x/mod/module"
-	"golang.org/x/pkgsite/internal/derrors"
-	"golang.org/x/pkgsite/internal/proxy"
-)
-
-// An fsModuleGetter gets modules from a directory in the filesystem
-// that is organized like the proxy, with paths that correspond to proxy
-// URLs. An example of such a directory is $(go env GOMODCACHE)/cache/download.
-type fsModuleGetter struct {
-	dir string
-}
-
-// NewFSModuleGetter return a ModuleGetter that reads modules from a filesystem
-// directory organized like the proxy.
-func NewFSModuleGetter(dir string) ModuleGetter {
-	return &fsModuleGetter{dir: dir}
-}
-
-// Info returns basic information about the module.
-func (g *fsModuleGetter) Info(ctx context.Context, path, version string) (_ *proxy.VersionInfo, err error) {
-	defer derrors.Wrap(&err, "fsModuleGetter.Info(%q, %q)", path, version)
-
-	data, err := g.readFile(path, version, "info")
-	if err != nil {
-		return nil, err
-	}
-	var info proxy.VersionInfo
-	if err := json.Unmarshal(data, &info); err != nil {
-		return nil, err
-	}
-	return &info, nil
-}
-
-// Mod returns the contents of the module's go.mod file.
-func (g *fsModuleGetter) Mod(ctx context.Context, path, version string) (_ []byte, err error) {
-	defer derrors.Wrap(&err, "fsModuleGetter.Mod(%q, %q)", path, version)
-
-	return g.readFile(path, version, "mod")
-}
-
-// FS returns an FS for the module's zip file.
-func (g *fsModuleGetter) FS(ctx context.Context, path, version string) (_ fs.FS, err error) {
-	defer derrors.Wrap(&err, "fsModuleGetter.FS(%q, %q)", path, version)
-
-	data, err := g.readFile(path, version, "zip")
-	if err != nil {
-		return nil, err
-	}
-	return zip.NewReader(bytes.NewReader(data), int64(len(data)))
-}
-
-// ZipSize returns the approximate size of the zip file in bytes.
-func (g *fsModuleGetter) ZipSize(ctx context.Context, path, version string) (int64, error) {
-	return 0, errors.New("fsModuleGetter.ZipSize unimplemented")
-}
-
-func (g *fsModuleGetter) readFile(path, version, suffix string) (_ []byte, err error) {
-	epath, err := g.escapedPath(path, version, suffix)
-	if err != nil {
-		return nil, err
-	}
-	f, err := os.Open(epath)
-	if err != nil {
-		return nil, err
-	}
-	defer f.Close()
-	return ioutil.ReadAll(f)
-}
-
-func (g *fsModuleGetter) escapedPath(modulePath, version, suffix string) (string, error) {
-	ep, err := module.EscapePath(modulePath)
-	if err != nil {
-		return "", fmt.Errorf("path: %v: %w", err, derrors.InvalidArgument)
-	}
-	ev, err := module.EscapeVersion(version)
-	if err != nil {
-		return "", fmt.Errorf("version: %v: %w", err, derrors.InvalidArgument)
-	}
-	return filepath.Join(g.dir, ep, "@v", fmt.Sprintf("%s.%s", ev, suffix)), nil
-}
diff --git a/internal/fetch/getters.go b/internal/fetch/getters.go
index 8b05250..89591cd 100644
--- a/internal/fetch/getters.go
+++ b/internal/fetch/getters.go
@@ -4,13 +4,43 @@
 
 package fetch
 
-import (
-	"context"
-	"io/fs"
+// The ModuleGetter interface and its implementations.
 
+import (
+	"archive/zip"
+	"bytes"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"io/fs"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"golang.org/x/mod/modfile"
+	"golang.org/x/mod/module"
+	"golang.org/x/pkgsite/internal/derrors"
 	"golang.org/x/pkgsite/internal/proxy"
 )
 
+// ModuleGetter gets module data.
+type ModuleGetter interface {
+	// Info returns basic information about the module.
+	Info(ctx context.Context, path, version string) (*proxy.VersionInfo, error)
+	// Mod returns the contents of the module's go.mod file.
+	Mod(ctx context.Context, path, version string) ([]byte, error)
+	// FS returns an FS for the module's contents. The FS should match the format
+	// of a module zip file.
+	FS(ctx context.Context, path, version string) (fs.FS, error)
+	// ZipSize returns the approximate size of the zip file in bytes.
+	// It is used only for load-shedding.
+	ZipSize(ctx context.Context, path, version string) (int64, error)
+}
+
 type proxyModuleGetter struct {
 	prox *proxy.Client
 }
@@ -40,3 +70,196 @@
 func (g *proxyModuleGetter) ZipSize(ctx context.Context, path, version string) (int64, error) {
 	return g.prox.ZipSize(ctx, path, version)
 }
+
+// Version and commit time are pre specified when fetching a local module, as these
+// fields are normally obtained from a proxy.
+var (
+	LocalVersion    = "v0.0.0"
+	LocalCommitTime = time.Time{}
+)
+
+// A directoryModuleGetter is a ModuleGetter whose source is a directory in the file system that contains
+// a module's files.
+type directoryModuleGetter struct {
+	modulePath string
+	dir        string
+}
+
+// NewDirectoryModuleGetter returns a ModuleGetter for reading a module from a directory.
+func NewDirectoryModuleGetter(modulePath, dir string) (*directoryModuleGetter, error) {
+	if modulePath == "" {
+		goModBytes, err := ioutil.ReadFile(filepath.Join(dir, "go.mod"))
+		if err != nil {
+			return nil, fmt.Errorf("cannot obtain module path for %q (%v): %w", dir, err, derrors.BadModule)
+		}
+		modulePath = modfile.ModulePath(goModBytes)
+		if modulePath == "" {
+			return nil, fmt.Errorf("go.mod in %q has no module path: %w", dir, derrors.BadModule)
+		}
+	}
+	return &directoryModuleGetter{
+		dir:        dir,
+		modulePath: modulePath,
+	}, nil
+}
+
+func (g *directoryModuleGetter) checkPath(path string) error {
+	if path != g.modulePath {
+		return fmt.Errorf("given module path %q does not match %q for directory %q: %w",
+			path, g.modulePath, g.dir, derrors.NotFound)
+	}
+	return nil
+}
+
+// Info returns basic information about the module.
+func (g *directoryModuleGetter) Info(ctx context.Context, path, version string) (*proxy.VersionInfo, error) {
+	if err := g.checkPath(path); err != nil {
+		return nil, err
+	}
+	return &proxy.VersionInfo{
+		Version: LocalVersion,
+		Time:    LocalCommitTime,
+	}, nil
+}
+
+// Mod returns the contents of the module's go.mod file.
+// If the file does not exist, it returns a synthesized one.
+func (g *directoryModuleGetter) Mod(ctx context.Context, path, version string) ([]byte, error) {
+	if err := g.checkPath(path); err != nil {
+		return nil, err
+	}
+	data, err := ioutil.ReadFile(filepath.Join(g.dir, "go.mod"))
+	if errors.Is(err, os.ErrNotExist) {
+		return []byte(fmt.Sprintf("module %s\n", g.modulePath)), nil
+	}
+	return data, err
+}
+
+// FS returns an fs.FS for the module.
+func (g *directoryModuleGetter) FS(ctx context.Context, path, version string) (fs.FS, error) {
+	if err := g.checkPath(path); err != nil {
+		return nil, err
+	}
+	return createZipReader(g.dir, path, LocalVersion)
+}
+
+// ZipSize returns the approximate size of the zip file in bytes.
+func (g *directoryModuleGetter) ZipSize(ctx context.Context, path, version string) (int64, error) {
+	return 0, errors.New("directoryModuleGetter.ZipSize unimplemented")
+}
+
+// createZipReader creates a zip file from a directory given a local path and
+// returns a zip.Reader to be passed to processZipFile. The purpose of the
+// function is to transform a local go module into a zip file to be processed by
+// existing functions.
+func createZipReader(localPath, modulePath, version string) (*zip.Reader, error) {
+	buf := new(bytes.Buffer)
+	w := zip.NewWriter(buf)
+	err := filepath.Walk(localPath, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+		if info.IsDir() {
+			return nil
+		}
+
+		readFrom, err := os.Open(path)
+		if err != nil {
+			return err
+		}
+		defer readFrom.Close()
+
+		writeTo, err := w.Create(filepath.Join(moduleVersionDir(modulePath, version), strings.TrimPrefix(path, localPath)))
+		if err != nil {
+			return err
+		}
+
+		_, err = io.Copy(writeTo, readFrom)
+		return err
+	})
+	if err != nil {
+		return nil, err
+	}
+	if err := w.Close(); err != nil {
+		return nil, err
+	}
+
+	reader := bytes.NewReader(buf.Bytes())
+	return zip.NewReader(reader, reader.Size())
+}
+
+// An fsModuleGetter gets modules from a directory in the filesystem
+// that is organized like the proxy, with paths that correspond to proxy
+// URLs. An example of such a directory is $(go env GOMODCACHE)/cache/download.
+type fsModuleGetter struct {
+	dir string
+}
+
+// NewFSModuleGetter return a ModuleGetter that reads modules from a filesystem
+// directory organized like the proxy.
+func NewFSModuleGetter(dir string) ModuleGetter {
+	return &fsModuleGetter{dir: dir}
+}
+
+// Info returns basic information about the module.
+func (g *fsModuleGetter) Info(ctx context.Context, path, version string) (_ *proxy.VersionInfo, err error) {
+	defer derrors.Wrap(&err, "fsModuleGetter.Info(%q, %q)", path, version)
+
+	data, err := g.readFile(path, version, "info")
+	if err != nil {
+		return nil, err
+	}
+	var info proxy.VersionInfo
+	if err := json.Unmarshal(data, &info); err != nil {
+		return nil, err
+	}
+	return &info, nil
+}
+
+// Mod returns the contents of the module's go.mod file.
+func (g *fsModuleGetter) Mod(ctx context.Context, path, version string) (_ []byte, err error) {
+	defer derrors.Wrap(&err, "fsModuleGetter.Mod(%q, %q)", path, version)
+
+	return g.readFile(path, version, "mod")
+}
+
+// FS returns an FS for the module's zip file.
+func (g *fsModuleGetter) FS(ctx context.Context, path, version string) (_ fs.FS, err error) {
+	defer derrors.Wrap(&err, "fsModuleGetter.FS(%q, %q)", path, version)
+
+	data, err := g.readFile(path, version, "zip")
+	if err != nil {
+		return nil, err
+	}
+	return zip.NewReader(bytes.NewReader(data), int64(len(data)))
+}
+
+// ZipSize returns the approximate size of the zip file in bytes.
+func (g *fsModuleGetter) ZipSize(ctx context.Context, path, version string) (int64, error) {
+	return 0, errors.New("fsModuleGetter.ZipSize unimplemented")
+}
+
+func (g *fsModuleGetter) readFile(path, version, suffix string) (_ []byte, err error) {
+	epath, err := g.escapedPath(path, version, suffix)
+	if err != nil {
+		return nil, err
+	}
+	f, err := os.Open(epath)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+	return ioutil.ReadAll(f)
+}
+
+func (g *fsModuleGetter) escapedPath(modulePath, version, suffix string) (string, error) {
+	ep, err := module.EscapePath(modulePath)
+	if err != nil {
+		return "", fmt.Errorf("path: %v: %w", err, derrors.InvalidArgument)
+	}
+	ev, err := module.EscapeVersion(version)
+	if err != nil {
+		return "", fmt.Errorf("version: %v: %w", err, derrors.InvalidArgument)
+	}
+	return filepath.Join(g.dir, ep, "@v", fmt.Sprintf("%s.%s", ev, suffix)), nil
+}
diff --git a/internal/fetch/fetchlocal_test.go b/internal/fetch/getters_test.go
similarity index 100%
rename from internal/fetch/fetchlocal_test.go
rename to internal/fetch/getters_test.go