internal: do not default gopkg.in paths to symbol mode
A gopkg.in path will have the structure gopkg.in/<name>.vN.
Do not redirect searches for <name>.vN to symbol mode by default.
For golang/go#44142
Change-Id: I8e666bd9a1dc2d5fed31f6a1b3512eeda771abc6
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/346111
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/internal/domain.go b/internal/domain.go
index 8bdb07c..b3aa868 100644
--- a/internal/domain.go
+++ b/internal/domain.go
@@ -4,6 +4,12 @@
package internal
+import (
+ "strings"
+
+ "golang.org/x/mod/semver"
+)
+
// TopLevelDomains contains all of the top level domains in the discovery
// database.
var TopLevelDomains = map[string]bool{
@@ -184,3 +190,18 @@
"yandex": true,
"zone": true,
}
+
+// IsGoPkgInPathElement reports whether p is an element of a gopkg.in path.
+// It returns true if p has "gopkg.in" as a prefix, or the suffix is a major
+// version, for example "yaml.v2".
+func IsGoPkgInPathElement(p string) bool {
+ if strings.HasPrefix(strings.ToLower(p), "gopkg.in") {
+ return true
+ }
+ parts := strings.Split(p, ".")
+ if len(parts) <= 1 {
+ return false
+ }
+ maj := parts[len(parts)-1]
+ return semver.Major(maj) == maj
+}
diff --git a/internal/frontend/search.go b/internal/frontend/search.go
index 24e538f..172e6d5 100644
--- a/internal/frontend/search.go
+++ b/internal/frontend/search.go
@@ -375,19 +375,22 @@
if prefix := searchModePackage + ":"; strings.HasPrefix(q, prefix) {
return strings.TrimPrefix(q, prefix), false
}
- if isPackageDotSymbol(q) {
+ if shouldDefaultToSymbolSearch(q) {
return q, true
}
return q, strings.TrimSpace(r.FormValue("m")) == searchModeSymbol
}
-// isPackageDotSymbol reports whether the search query is of the form
+// shouldDefaultToSymbolSearch reports whether the search query is of the form
// <package>.<symbol>. The <symbol> component should not be a top-level domain
// that is in our database.
-func isPackageDotSymbol(q string) bool {
+func shouldDefaultToSymbolSearch(q string) bool {
if len(strings.Fields(q)) != 1 || !strings.ContainsAny(q, ".") {
return false
}
+ if internal.IsGoPkgInPathElement(q) {
+ return false
+ }
parts := strings.Split(q, ".")
return !internal.TopLevelDomains[parts[len(parts)-1]]
}
diff --git a/internal/frontend/search_test.go b/internal/frontend/search_test.go
index 3958ad4..3e86bf2 100644
--- a/internal/frontend/search_test.go
+++ b/internal/frontend/search_test.go
@@ -397,7 +397,7 @@
}
}
-func TestIsPackageDotSymbol(t *testing.T) {
+func TestShouldDefaultToSymbolSearch(t *testing.T) {
for _, test := range []struct {
q string
want bool
@@ -409,9 +409,11 @@
{"sql", false},
{"sql.DB", true},
{"sql.DB.Begin", true},
+ {"yaml.v2", false},
+ {"gopkg.in", false},
} {
t.Run(test.q, func(t *testing.T) {
- got := isPackageDotSymbol(test.q)
+ got := shouldDefaultToSymbolSearch(test.q)
if diff := cmp.Diff(test.want, got); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
}
diff --git a/tests/search/scripts/default.txt b/tests/search/scripts/default.txt
index 8d76491..097f5d8 100644
--- a/tests/search/scripts/default.txt
+++ b/tests/search/scripts/default.txt
@@ -13,3 +13,7 @@
gopkg.in search defaults to package mode
[package] gopkg.in
gopkg.in/foo.v1
+
+gopkg.in element search defaults to package mode
+[package] foo.v1
+gopkg.in/foo.v1