internal/fetch: avoid creating zip

As the culmination of the last few CLs, we no longer need to build a
zip file when reading a module from a local directory.

Now `go run ./cmd/pkgsite .` takes about 12 seconds, instead of too long
to wait for.

For golang/go#47834

Change-Id: I73bdcefe01068432de37c53e3caeebf2b161c9f6
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/343964
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/internal/fetch/fetch.go b/internal/fetch/fetch.go
index 16071fb..d5ce057 100644
--- a/internal/fetch/fetch.go
+++ b/internal/fetch/fetch.go
@@ -392,12 +392,6 @@
 	return false, ""
 }
 
-// moduleVersionDir formats the content subdirectory for the given
-// modulePath and version.
-func moduleVersionDir(modulePath, version string) string {
-	return fmt.Sprintf("%s@%s", modulePath, version)
-}
-
 type FetchInfo struct {
 	ModulePath string
 	Version    string
diff --git a/internal/fetch/getters.go b/internal/fetch/getters.go
index 9355ed9..2471f4b 100644
--- a/internal/fetch/getters.go
+++ b/internal/fetch/getters.go
@@ -13,12 +13,10 @@
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io"
 	"io/fs"
 	"io/ioutil"
 	"os"
 	"path/filepath"
-	"strings"
 	"time"
 
 	"golang.org/x/mod/modfile"
@@ -150,11 +148,7 @@
 	if err := g.checkPath(path); err != nil {
 		return nil, err
 	}
-	zr, err := createZipReader(g.dir, path, LocalVersion)
-	if err != nil {
-		return nil, err
-	}
-	return fs.Sub(zr, path+"@"+LocalVersion)
+	return os.DirFS(g.dir), nil
 }
 
 // ZipSize returns the approximate size of the zip file in bytes.
@@ -162,46 +156,6 @@
 	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.
diff --git a/internal/fetch/helper_test.go b/internal/fetch/helper_test.go
index db49a89..bb9f2e1 100644
--- a/internal/fetch/helper_test.go
+++ b/internal/fetch/helper_test.go
@@ -167,7 +167,7 @@
 	if err != nil {
 		t.Fatalf("couldn't create test files")
 	}
-	defer os.RemoveAll(directory)
+	t.Cleanup(func() { os.RemoveAll(directory) })
 
 	modulePath := mod.ModulePath
 	g, err := NewDirectoryModuleGetter(modulePath, directory)
@@ -179,11 +179,7 @@
 		return got, nil
 	}
 
-	zipReader, err := createZipReader(directory, modulePath, LocalVersion)
-	if err != nil {
-		t.Fatal("couldn't create zip reader")
-	}
-	d := licenses.NewDetector(modulePath, LocalVersion, zipReader, func(format string, args ...interface{}) {
+	d := licenses.NewDetectorFS(modulePath, LocalVersion, os.DirFS(directory), func(format string, args ...interface{}) {
 		log.Infof(ctx, format, args...)
 	})
 	return got, d