internal: support "all" in BuildContext
Handle BuildContexts where one or more parts are "all".
These should only occur when searching for a matching Documentation,
not sorting. (Because we sort only when there is more than one
Documentation, and if there is an all/all Documentation then there
aren't any others.)
For golang/go#37232
Change-Id: I898aba8f73d2682798d56c47cc6773709f10c702
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/290094
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/build_context.go b/internal/build_context.go
index 76ae015..9e7db80 100644
--- a/internal/build_context.go
+++ b/internal/build_context.go
@@ -11,6 +11,9 @@
GOOS, GOARCH string
}
+// All represents all values for a build context element (GOOS or GOARCH).
+const All = "all"
+
// BuildContexts are the build contexts we check when loading a package (see
// internal/fetch/load.go).
// We store documentation for all of the listed contexts.
@@ -25,6 +28,14 @@
// CompareBuildContexts returns a negative number, 0, or a positive number depending on
// the relative positions of c1 and c2 in BuildContexts.
func CompareBuildContexts(c1, c2 BuildContext) int {
+ if c1 == c2 {
+ return 0
+ }
+ // We should never see a BuildContext with "all" here.
+ if c1.GOOS == All || c1.GOARCH == All || c2.GOOS == All || c2.GOARCH == All {
+ panic("BuildContext with 'all'")
+ }
+
pos := func(c BuildContext) int {
for i, d := range BuildContexts {
if c == d {
@@ -44,12 +55,12 @@
// DocumentationForBuildContext returns the first Documentation the list that
// matches the BuildContext, or nil if none does. A Documentation matches if its
// GOOS and GOARCH fields are the same as those of the BuildContext, or if the
-// BuildContext field is empty. That is, empty BuildContext fields act as
-// wildcards. So the zero BuildContext will match the first element of docs, if
-// there is one.
+// Documentation field is "all", or if the BuildContext field is empty. That is,
+// empty BuildContext fields act as wildcards. So the zero BuildContext will
+// match the first element of docs, if there is one.
func DocumentationForBuildContext(docs []*Documentation, bc BuildContext) *Documentation {
for _, d := range docs {
- if (bc.GOOS == "" || bc.GOOS == d.GOOS) && (bc.GOARCH == "" || bc.GOARCH == d.GOARCH) {
+ if (bc.GOOS == "" || d.GOOS == All || bc.GOOS == d.GOOS) && (bc.GOARCH == "" || d.GOARCH == All || bc.GOARCH == d.GOARCH) {
return d
}
}
diff --git a/internal/build_context_test.go b/internal/build_context_test.go
index c4e1fc1..1c05577 100644
--- a/internal/build_context_test.go
+++ b/internal/build_context_test.go
@@ -7,21 +7,33 @@
import "testing"
func TestCompareBuildContexts(t *testing.T) {
+ check := func(c1, c2 BuildContext, want int) {
+ t.Helper()
+ got := CompareBuildContexts(c1, c2)
+ switch want {
+ case 0:
+ if got != 0 {
+ t.Errorf("%v vs. %v: got %d, want 0", c1, c2, got)
+ }
+ case 1:
+ if got <= 0 {
+ t.Errorf("%v vs. %v: got %d, want > 0", c1, c2, got)
+ }
+ case -1:
+ if got >= 0 {
+ t.Errorf("%v vs. %v: got %d, want < 0", c1, c2, got)
+ }
+ }
+ }
+
for i, c1 := range BuildContexts {
- if got := CompareBuildContexts(c1, c1); got != 0 {
- t.Errorf("%v: got %d, want 0", c1, got)
- }
+ check(c1, c1, 0)
for _, c2 := range BuildContexts[i+1:] {
- if got := CompareBuildContexts(c1, c2); got >= 0 {
- t.Errorf("%v, %v: got %d, want < 0", c1, c2, got)
- }
- if got := CompareBuildContexts(c2, c1); got <= 0 {
- t.Errorf("%v, %v: got %d, want > 0", c2, c1, got)
- }
+ check(c1, c2, -1)
+ check(c2, c1, 1)
}
}
- got := CompareBuildContexts(BuildContext{"?", "?"}, BuildContexts[len(BuildContexts)-1])
- if got <= 0 {
- t.Errorf("unknown vs. last: got %d, want > 0", got)
- }
+
+ // Special cases.
+ check(BuildContext{"?", "?"}, BuildContexts[len(BuildContexts)-1], 1) // unknown is last
}
diff --git a/internal/fetch/fetchdata_test.go b/internal/fetch/fetchdata_test.go
index dc7804a..e36e9f7 100644
--- a/internal/fetch/fetchdata_test.go
+++ b/internal/fetch/fetchdata_test.go
@@ -54,6 +54,8 @@
Path: "github.com/basic/foo",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "package foo exports a helpful constant.",
}},
Imports: []string{"net/http"},
@@ -124,6 +126,8 @@
Contents: "Another README FILE FOR TESTING.",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "package bar",
}},
},
@@ -133,6 +137,8 @@
Path: "github.com/my/module/foo",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "package foo",
}},
Imports: []string{"fmt", "github.com/my/module/bar"},
@@ -178,6 +184,8 @@
Path: "no.mod/module/p",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "Package p is inside a module where a go.mod file hasn't been explicitly added yet.",
}},
},
@@ -241,6 +249,8 @@
Path: "bad.mod/module/good",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "Package good is inside a module that has bad packages.",
}},
},
@@ -397,6 +407,8 @@
Path: "nonredistributable.mod/module/bar",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "package bar",
}},
},
@@ -406,6 +418,8 @@
Path: "nonredistributable.mod/module/bar/baz",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "package baz",
}},
},
@@ -419,6 +433,8 @@
Contents: "README FILE SHOW UP HERE BUT WILL BE REMOVED BEFORE DB INSERT",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "package foo",
}},
Imports: []string{"fmt", "github.com/my/module/bar"},
@@ -468,7 +484,7 @@
Name: "foo",
Path: "bad.import.path.com/good/import/path",
},
- Documentation: []*internal.Documentation{{}},
+ Documentation: []*internal.Documentation{{GOOS: internal.All, GOARCH: internal.All}},
},
},
},
@@ -527,6 +543,8 @@
Path: "doc.test/permalink",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "Package permalink is for testing the heading permalink documentation rendering feature.",
}},
},
@@ -566,6 +584,8 @@
Path: "bigdoc.test",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "This documentation is big.",
}},
},
@@ -674,6 +694,8 @@
Path: "builtin",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "Package builtin provides documentation for Go's predeclared identifiers.",
}},
},
@@ -720,6 +742,8 @@
Path: "context",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "Package context defines the Context type, which carries deadlines, cancelation signals, and other request-scoped values across API boundaries and between processes.",
}},
Imports: []string{"errors", "fmt", "reflect", "sync", "time"},
@@ -735,6 +759,8 @@
Path: "encoding/json",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "Package json implements encoding and decoding of JSON as defined in RFC 7159.",
}},
Imports: []string{
@@ -761,6 +787,8 @@
Path: "errors",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "Package errors implements functions to manipulate errors.",
}},
},
@@ -771,6 +799,8 @@
},
Imports: []string{"errors", "fmt", "io", "os", "reflect", "sort", "strconv", "strings", "time"},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "Package flag implements command-line flag parsing.",
}},
},
@@ -807,6 +837,8 @@
Path: "github.com/my/module/foo",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "package foo exports a helpful constant.",
}},
},
@@ -843,6 +875,8 @@
Path: "github.com/my/module/foo",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "package foo exports a helpful constant.",
}},
},
@@ -892,6 +926,8 @@
Path: path + "/example",
},
Documentation: []*internal.Documentation{{
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: "Package example contains examples.",
}},
},
diff --git a/internal/fetch/load.go b/internal/fetch/load.go
index bc13b91..f5b149f 100644
--- a/internal/fetch/load.go
+++ b/internal/fetch/load.go
@@ -112,8 +112,8 @@
name: name,
imports: imports,
docs: []*internal.Documentation{{
- GOOS: bc.GOOS,
- GOARCH: bc.GOARCH,
+ GOOS: internal.All,
+ GOARCH: internal.All,
Synopsis: synopsis,
Source: source,
}},
@@ -149,6 +149,14 @@
pkg.docs = append(pkg.docs, doc)
}
}
+ // If all the build contexts succeeded and had the same set of files, then
+ // assume that the package doc is valid for all build contexts. Represent
+ // this with a single Documentation whose GOOS and GOARCH are both "all".
+ if len(docsByFiles) == 1 && len(pkg.docs) == len(internal.BuildContexts) {
+ pkg.docs = pkg.docs[:1]
+ pkg.docs[0].GOOS = internal.All
+ pkg.docs[0].GOARCH = internal.All
+ }
return pkg, nil
}
diff --git a/internal/postgres/unit_test.go b/internal/postgres/unit_test.go
index a3daca9..ea53d45 100644
--- a/internal/postgres/unit_test.go
+++ b/internal/postgres/unit_test.go
@@ -449,13 +449,21 @@
// Add a module that has documentation for two Go build contexts.
m = sample.Module("a.com/twodoc", "v1.2.3", "p")
pkg := m.Packages()[0]
- doc2 := &internal.Documentation{
- GOOS: "windows",
- GOARCH: "amd64",
- Synopsis: pkg.Documentation[0].Synopsis + " 2",
- Source: pkg.Documentation[0].Source,
+ docs2 := []*internal.Documentation{
+ {
+ GOOS: "linux",
+ GOARCH: "amd64",
+ Synopsis: sample.Synopsis + " for linux",
+ Source: sample.Documentation.Source,
+ },
+ {
+ GOOS: "windows",
+ GOARCH: "amd64",
+ Synopsis: sample.Synopsis + " for windows",
+ Source: sample.Documentation.Source,
+ },
}
- pkg.Documentation = append(pkg.Documentation, doc2)
+ pkg.Documentation = docs2
if err := testDB.InsertModule(ctx, m); err != nil {
t.Fatal(err)
}
@@ -578,7 +586,8 @@
u := unit("a.com/twodoc/p", "a.com/twodoc", "v1.2.3", "p",
nil,
[]string{"p"})
- u.Documentation = append(u.Documentation, doc2)
+ u.Documentation = docs2
+ u.Subdirectories[0].Synopsis = docs2[0].Synopsis
return u
}(),
},
diff --git a/internal/testing/sample/sample.go b/internal/testing/sample/sample.go
index 17b2f24..f284aa9 100644
--- a/internal/testing/sample/sample.go
+++ b/internal/testing/sample/sample.go
@@ -62,8 +62,8 @@
Synopsis = "This is a package synopsis"
ReadmeFilePath = "README.md"
ReadmeContents = "readme"
- GOOS = "linux"
- GOARCH = "amd64"
+ GOOS = internal.All
+ GOARCH = internal.All
)
// LicenseCmpOpts are options to use when comparing licenses with the cmp package.