internal/stdlib: support opening local repo
By calling stdlib.SetGoRepoPath, users can point to a local clone of
the Go repo for stdlib to use. This can save download time. The intent
is to use it for cmd/pkgsite.
Change-Id: I20d89f283b7b0b4f333599846eee1038d09cb50e
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/347404
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/internal/stdlib/stdlib.go b/internal/stdlib/stdlib.go
index 2c57d76..3b05de4 100644
--- a/internal/stdlib/stdlib.go
+++ b/internal/stdlib/stdlib.go
@@ -19,6 +19,7 @@
"path/filepath"
"regexp"
"strings"
+ "sync"
"time"
"golang.org/x/mod/semver"
@@ -199,12 +200,35 @@
TestDevFuzzVersion = "v0.0.0-20190904010203-12de34vf56uz"
)
+var (
+ goRepoPathMu sync.Mutex
+ goRepoPath string
+)
+
+// SetGoRepoPath tells this package to obtain the Go repo from the
+// local filesystem at path, instead of cloning it.
+func SetGoRepoPath(path string) {
+ goRepoPathMu.Lock()
+ defer goRepoPathMu.Unlock()
+ goRepoPath = path
+
+}
+
+func getGoRepoPath() string {
+ goRepoPathMu.Lock()
+ defer goRepoPathMu.Unlock()
+ return goRepoPath
+}
+
// getGoRepo returns a repo object for the Go repo at version.
func getGoRepo(version string) (_ *git.Repository, _ plumbing.ReferenceName, err error) {
defer derrors.Wrap(&err, "getGoRepo(%q)", version)
if UseTestData {
return getTestGoRepo(version)
}
+ if path := getGoRepoPath(); path != "" {
+ return openGoRepo(path, version)
+ }
return cloneGoRepo(version)
}
@@ -213,16 +237,9 @@
func cloneGoRepo(v string) (_ *git.Repository, ref plumbing.ReferenceName, err error) {
defer derrors.Wrap(&err, "cloneGoRepo(%q)", v)
- if v == version.Master {
- ref = plumbing.HEAD
- } else if SupportedBranches[v] {
- ref = plumbing.NewBranchReferenceName(v)
- } else {
- tag, err := TagForVersion(v)
- if err != nil {
- return nil, "", err
- }
- ref = plumbing.NewTagReferenceName(tag)
+ ref, err = refNameForVersion(v)
+ if err != nil {
+ return nil, "", err
}
repo, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
URL: GoRepoURL,
@@ -237,6 +254,33 @@
return repo, ref, nil
}
+func openGoRepo(path, v string) (_ *git.Repository, _ plumbing.ReferenceName, err error) {
+ defer derrors.Wrap(&err, "openGoRepo(%q)", v)
+ repo, err := git.PlainOpen(path)
+ if err != nil {
+ return nil, "", err
+ }
+ ref, err := refNameForVersion(v)
+ if err != nil {
+ return nil, "", err
+ }
+ return repo, ref, nil
+}
+
+func refNameForVersion(v string) (plumbing.ReferenceName, error) {
+ if v == version.Master {
+ return plumbing.HEAD, nil
+ }
+ if SupportedBranches[v] {
+ return plumbing.NewBranchReferenceName(v), nil
+ }
+ tag, err := TagForVersion(v)
+ if err != nil {
+ return "", err
+ }
+ return plumbing.NewTagReferenceName(tag), nil
+}
+
// getTestGoRepo gets a Go repo for testing.
func getTestGoRepo(v string) (_ *git.Repository, _ plumbing.ReferenceName, err error) {
defer derrors.Wrap(&err, "getTestGoRepo(%q)", v)
diff --git a/internal/stdlib/stdlib_test.go b/internal/stdlib/stdlib_test.go
index 0e20402..811c8c1 100644
--- a/internal/stdlib/stdlib_test.go
+++ b/internal/stdlib/stdlib_test.go
@@ -15,7 +15,10 @@
"golang.org/x/pkgsite/internal/version"
)
-var clone = flag.Bool("clone", false, "test actual clones of the Go repo")
+var (
+ clone = flag.Bool("clone", false, "test actual clones of the Go repo")
+ repoPath = flag.String("path", "", "path to Go repo to test")
+)
func TestTagForVersion(t *testing.T) {
for _, test := range []struct {
@@ -150,23 +153,34 @@
}
}
-func TestContentDirClone(t *testing.T) {
- if !*clone {
- t.Skip("-clone not supplied")
+func TestContentDirCloneAndOpen(t *testing.T) {
+ if !*clone && *repoPath == "" {
+ t.Skip("-clone and -path not supplied")
}
- for _, resolvedVersion := range []string{
- "v1.3.2",
- "v1.14.6",
- version.Master,
- version.Latest,
- } {
- t.Run(resolvedVersion, func(t *testing.T) {
- cdir, _, _, err := ContentDir(resolvedVersion)
- if err != nil {
- t.Fatal(err)
- }
- checkContentDirFiles(t, cdir, resolvedVersion)
- })
+
+ run := func(t *testing.T) {
+ for _, resolvedVersion := range []string{
+ "v1.3.2",
+ "v1.14.6",
+ version.Master,
+ version.Latest,
+ } {
+ t.Run(resolvedVersion, func(t *testing.T) {
+ cdir, _, _, err := ContentDir(resolvedVersion)
+ if err != nil {
+ t.Fatal(err)
+ }
+ checkContentDirFiles(t, cdir, resolvedVersion)
+ })
+ }
+ }
+
+ if *clone {
+ t.Run("clone", run)
+ }
+ if *repoPath != "" {
+ SetGoRepoPath(*repoPath)
+ t.Run("open", run)
}
}