internal/godoc: delete Corpus
There's nothing left in Corpus but the file system and the API database.
Hoist them into Presentation and delete the Corpus itself.
Change-Id: I2cb61b77122b2f7216b0b2a96fd6b48e29eae189
Reviewed-on: https://go-review.googlesource.com/c/website/+/317651
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/cmd/golangorg/godoc_test.go b/cmd/golangorg/godoc_test.go
index 0900aba..a9d5b8b 100644
--- a/cmd/golangorg/godoc_test.go
+++ b/cmd/golangorg/godoc_test.go
@@ -176,8 +176,11 @@
releaseTag string // optional release tag that must be in go/build.ReleaseTags
}{
{
- path: "/",
- contains: []string{"Go is an open source programming language"},
+ path: "/",
+ contains: []string{
+ "Go is an open source programming language",
+ "Binary distributions available for",
+ },
},
{
path: "/conduct",
diff --git a/cmd/golangorg/main.go b/cmd/golangorg/main.go
index 4f9e280..be8205c 100644
--- a/cmd/golangorg/main.go
+++ b/cmd/golangorg/main.go
@@ -78,12 +78,7 @@
}
fsys = unionFS{content, os.DirFS(*goroot)}
- corpus := godoc.NewCorpus(fsys)
- // Initialize the version info before readTemplates, which saves
- // the map value in a method value.
- corpus.InitVersionInfo()
-
- pres = godoc.NewPresentation(corpus)
+ pres = godoc.NewPresentation(fsys)
pres.GoogleCN = googleCN
readTemplates(pres)
diff --git a/cmd/golangorg/release_test.go b/cmd/golangorg/release_test.go
index 98c54c5..9dbbaf5 100644
--- a/cmd/golangorg/release_test.go
+++ b/cmd/golangorg/release_test.go
@@ -27,7 +27,7 @@
origFS, origPres := fsys, pres
defer func() { fsys, pres = origFS, origPres }()
fsys = website.Content
- pres = godoc.NewPresentation(godoc.NewCorpus(fsys))
+ pres = godoc.NewPresentation(fsys)
readTemplates(pres)
mux := registerHandlers(pres)
diff --git a/internal/api/api.go b/internal/api/api.go
index 59e6740..a9669f2 100644
--- a/internal/api/api.go
+++ b/internal/api/api.go
@@ -12,8 +12,8 @@
import (
"bufio"
- "go/build"
- "os"
+ "io/fs"
+ "path"
"path/filepath"
"sort"
"strconv"
@@ -64,15 +64,10 @@
return ""
}
-func Load() (DB, error) {
- var apiGlob string
- if os.Getenv("GOROOT") == "" {
- apiGlob = filepath.Join(build.Default.GOROOT, "api", "go*.txt")
- } else {
- apiGlob = filepath.Join(os.Getenv("GOROOT"), "api", "go*.txt")
- }
-
- files, err := filepath.Glob(apiGlob)
+// Load loads a database from fsys's api/go*.txt files.
+// Typically, fsys should be the root of a Go repository (a $GOROOT).
+func Load(fsys fs.FS) (DB, error) {
+ files, err := fs.Glob(fsys, "api/go*.txt")
if err != nil {
return nil, err
}
@@ -87,7 +82,7 @@
// when the symbol was added. See golang.org/issue/44081.
//
ver := func(name string) int {
- base := filepath.Base(name)
+ base := path.Base(name)
ver := strings.TrimPrefix(strings.TrimSuffix(base, ".txt"), "go1.")
if ver == "go1" {
return 0
@@ -98,7 +93,7 @@
sort.Slice(files, func(i, j int) bool { return ver(files[i]) > ver(files[j]) })
vp := new(parser)
for _, f := range files {
- if err := vp.parseFile(f); err != nil {
+ if err := vp.parseFile(fsys, f); err != nil {
return nil, err
}
}
@@ -116,8 +111,8 @@
// vp.res to VERSION, overwriting any previous value.
// As a special case, if goVERSION is "go1", it deletes
// from the map instead.
-func (vp *parser) parseFile(name string) error {
- f, err := os.Open(name)
+func (vp *parser) parseFile(fsys fs.FS, name string) error {
+ f, err := fsys.Open(name)
if err != nil {
return err
}
diff --git a/internal/api/api_test.go b/internal/api/api_test.go
index bfddc5d..64c8800 100644
--- a/internal/api/api_test.go
+++ b/internal/api/api_test.go
@@ -9,6 +9,8 @@
import (
"go/build"
+ "os"
+ "runtime"
"testing"
)
@@ -91,7 +93,7 @@
}
func TestAPIVersion(t *testing.T) {
- av, err := Load()
+ av, err := Load(os.DirFS(runtime.GOROOT()))
if err != nil {
t.Fatal(err)
}
diff --git a/internal/godoc/astfuncs.go b/internal/godoc/astfuncs.go
index 22e1bdc..f6cafd4 100644
--- a/internal/godoc/astfuncs.go
+++ b/internal/godoc/astfuncs.go
@@ -67,7 +67,6 @@
var pkgName, structName string
var apiInfo api.PkgDB
if gd, ok := x.(*ast.GenDecl); ok && pageInfo != nil && pageInfo.PDoc != nil &&
- p.Corpus != nil &&
gd.Tok == token.TYPE && len(gd.Specs) != 0 {
pkgName = pageInfo.PDoc.ImportPath
if ts, ok := gd.Specs[0].(*ast.TypeSpec); ok {
@@ -75,7 +74,7 @@
structName = ts.Name.Name
}
}
- apiInfo = p.Corpus.pkgAPIInfo[pkgName]
+ apiInfo = p.api[pkgName]
}
var out = w
diff --git a/internal/godoc/corpus.go b/internal/godoc/corpus.go
deleted file mode 100644
index 2bdb113..0000000
--- a/internal/godoc/corpus.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2013 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.
-
-//go:build go1.16
-// +build go1.16
-
-package godoc
-
-import (
- "io/fs"
-
- "golang.org/x/website/internal/api"
-)
-
-// A Corpus holds all the state related to serving and indexing a
-// collection of Go code.
-//
-// Construct a new Corpus with NewCorpus, then modify options,
-// then call its Init method.
-type Corpus struct {
- fs fs.FS
-
- // pkgAPIInfo contains the information about which package API
- // features were added in which version of Go.
- pkgAPIInfo api.DB
-}
-
-// NewCorpus returns a new Corpus from a filesystem.
-// The returned corpus has all indexing enabled and MaxResults set to 1000.
-// Change or set any options on Corpus before calling the Corpus.Init method.
-func NewCorpus(fsys fs.FS) *Corpus {
- c := &Corpus{
- fs: fsys,
- }
- return c
-}
diff --git a/internal/godoc/godoc.go b/internal/godoc/godoc.go
index 5b8ca55..ff0a202 100644
--- a/internal/godoc/godoc.go
+++ b/internal/godoc/godoc.go
@@ -38,8 +38,8 @@
}
func (p *Presentation) initFuncMap() {
- if p.Corpus == nil {
- panic("nil Presentation.Corpus")
+ if p.fs == nil {
+ panic("nil Presentation.fs")
}
p.templateFuncs = template.FuncMap{
"code": p.code,
@@ -48,7 +48,7 @@
p.funcMap = template.FuncMap{
// various helpers
"filename": filenameFunc,
- "since": p.Corpus.pkgAPIInfo.Func,
+ "since": p.api.Func,
// formatting of AST nodes
"node": p.nodeFunc,
diff --git a/internal/godoc/meta.go b/internal/godoc/meta.go
index b6b7791..0c5809e 100644
--- a/internal/godoc/meta.go
+++ b/internal/godoc/meta.go
@@ -12,6 +12,7 @@
"encoding/json"
"io/fs"
"log"
+ "path"
"strings"
)
@@ -21,28 +22,28 @@
jsonEnd = []byte("}-->")
)
-type Metadata struct {
- // Copied from document metadata
+type file struct {
+ // Copied from document metadata directives
Title string
Subtitle string
Template bool
Path string // URL path
FilePath string // filesystem path relative to goroot
+ Body []byte // content after metadata
}
-type MetaJSON struct {
+type metaJSON struct {
Title string
Subtitle string
Template bool
Redirect string // if set, redirect to other URL
}
-// extractMetadata extracts the MetaJSON from a byte slice.
-// It returns the Metadata value and the remaining data.
-// If no metadata is present the original byte slice is returned.
-//
-func extractMetadata(b []byte) (meta MetaJSON, tail []byte, err error) {
+// extractMetadata extracts the metaJSON from a byte slice.
+// It returns the metadata and the remaining text.
+// If no metadata is present, it returns an empty metaJSON and the original text.
+func extractMetadata(b []byte) (meta metaJSON, tail []byte, err error) {
tail = b
if !bytes.HasPrefix(b, jsonStart) {
return
@@ -59,66 +60,77 @@
return
}
-// MetadataFor returns the *Metadata for a given absolute path
-// or nil if none exists.
-func (c *Corpus) MetadataFor(path string) *Metadata {
- // Strip any .html or .md; it all names the same page.
+var join = path.Join
+
+// open returns the file for a given absolute path or nil if none exists.
+func open(fsys fs.FS, path string) *file {
+ // Strip trailing .html or .md or /; it all names the same page.
if strings.HasSuffix(path, ".html") {
path = strings.TrimSuffix(path, ".html")
} else if strings.HasSuffix(path, ".md") {
path = strings.TrimSuffix(path, ".md")
+ } else if path != "/" && strings.HasSuffix(path, "/") {
+ path = strings.TrimSuffix(path, "/")
}
- file := path + ".html"
- b, err := fs.ReadFile(c.fs, toFS(file))
- if err != nil {
- file = path + ".md"
- b, err = fs.ReadFile(c.fs, toFS(file))
- }
- if err != nil {
- // Special case for memory model and spec, which live
- // in the main Go repo's doc directory and therefore have not
- // been renamed to their serving paths.
- // We wait until the ReadFiles above have failed so that the
- // code works if these are ever moved to /ref/spec and /ref/mem.
- switch path {
- case "/ref/spec":
- if m := c.MetadataFor("/doc/go_spec"); m != nil {
- return m
- }
- case "/ref/mem":
- if m := c.MetadataFor("/doc/go_mem"); m != nil {
- return m
- }
+ files := []string{path + ".html", path + ".md", join(path, "index.html"), join(path, "index.md")}
+ var filePath string
+ var b []byte
+ var err error
+ for _, filePath = range files {
+ b, err = fs.ReadFile(fsys, toFS(filePath))
+ if err == nil {
+ break
}
- return nil
}
- js, _, err := extractMetadata(b)
+ // Special case for memory model and spec, which live
+ // in the main Go repo's doc directory and therefore have not
+ // been renamed to their serving paths.
+ // We wait until the ReadFiles above have failed so that the
+ // code works if these are ever moved to /ref/spec and /ref/mem.
+ if err != nil && path == "/ref/spec" {
+ return open(fsys, "/doc/go_spec")
+ }
+ if err != nil && path == "/ref/mem" {
+ return open(fsys, "/doc/go_mem")
+ }
+
if err != nil {
- log.Printf("MetadataFor %s: %v", path, err)
return nil
}
- meta := &Metadata{
- Title: js.Title,
- Subtitle: js.Subtitle,
- Template: js.Template,
- Path: path,
- FilePath: file,
- }
- if js.Redirect != "" {
- // Allow (placeholder) documents to declare a redirect.
- meta.Path = js.Redirect
- }
-
// Special case for memory model and spec, continued.
switch path {
case "/doc/go_spec":
- meta.Path = "/ref/spec"
+ path = "/ref/spec"
case "/doc/go_mem":
- meta.Path = "/ref/mem"
+ path = "/ref/mem"
}
- return meta
+ // If we read an index.md or index.html, the canonical path is without the index.md/index.html suffix.
+ if strings.HasSuffix(filePath, "/index.md") || strings.HasSuffix(filePath, "/index.html") {
+ path = filePath[:strings.LastIndex(filePath, "/")+1]
+ }
+
+ js, body, err := extractMetadata(b)
+ if err != nil {
+ log.Printf("extractMetadata %s: %v", path, err)
+ return nil
+ }
+
+ f := &file{
+ Title: js.Title,
+ Subtitle: js.Subtitle,
+ Template: js.Template,
+ Path: path,
+ FilePath: filePath,
+ Body: body,
+ }
+ if js.Redirect != "" {
+ // Allow (placeholder) documents to declare a redirect.
+ f.Path = js.Redirect
+ }
+
+ return f
}
diff --git a/internal/godoc/pres.go b/internal/godoc/pres.go
index 4aaa41b..5ce3c22 100644
--- a/internal/godoc/pres.go
+++ b/internal/godoc/pres.go
@@ -8,16 +8,20 @@
package godoc
import (
+ "io/fs"
+ "log"
"net/http"
"sync"
"text/template"
+ "golang.org/x/website/internal/api"
"golang.org/x/website/internal/pkgdoc"
)
-// Presentation generates output from a corpus.
+// Presentation generates output from a file system.
type Presentation struct {
- Corpus *Corpus
+ fs fs.FS
+ api api.DB
mux *http.ServeMux
fileServer http.Handler
@@ -42,19 +46,21 @@
templateFuncs template.FuncMap
}
-// NewPresentation returns a new Presentation from a corpus.
-func NewPresentation(c *Corpus) *Presentation {
- if c == nil {
- panic("nil Corpus")
+// NewPresentation returns a new Presentation from a file system.
+func NewPresentation(fsys fs.FS) *Presentation {
+ apiDB, err := api.Load(fsys)
+ if err != nil {
+ log.Fatalf("NewPresentation loading api: %v", err)
}
p := &Presentation{
- Corpus: c,
+ fs: fsys,
+ api: apiDB,
mux: http.NewServeMux(),
- fileServer: http.FileServer(http.FS(c.fs)),
+ fileServer: http.FileServer(http.FS(fsys)),
}
docs := &docServer{
p: p,
- d: pkgdoc.NewDocs(c.fs),
+ d: pkgdoc.NewDocs(fsys),
}
p.mux.Handle("/cmd/", docs)
p.mux.Handle("/pkg/", docs)
diff --git a/internal/godoc/server.go b/internal/godoc/server.go
index cdcd59c..4d3a740 100644
--- a/internal/godoc/server.go
+++ b/internal/godoc/server.go
@@ -203,8 +203,8 @@
return nil
}
-func (p *Presentation) serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
- src, err := fs.ReadFile(p.Corpus.fs, toFS(abspath))
+func (p *Presentation) serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
+ src, err := fs.ReadFile(p.fs, toFS(abspath))
if err != nil {
log.Printf("ReadFile: %s", err)
p.ServeError(w, r, relpath, err)
@@ -230,6 +230,10 @@
fmt.Fprintf(&buf, `<p><a href="/%s?m=text">View as plain text</a></p>`, htmlpkg.EscapeString(relpath))
+ title := "Text file"
+ if strings.HasSuffix(relpath, ".go") {
+ title = "Source file"
+ }
p.ServePage(w, Page{
Title: title,
SrcPath: relpath,
@@ -244,7 +248,7 @@
return
}
- list, err := fs.ReadDir(p.Corpus.fs, toFS(abspath))
+ list, err := fs.ReadDir(p.fs, toFS(abspath))
if err != nil {
p.ServeError(w, r, relpath, err)
return
@@ -267,15 +271,9 @@
})
}
-func (p *Presentation) ServeHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
- // get HTML body contents
- src, err := fs.ReadFile(p.Corpus.fs, toFS(abspath))
- if err != nil {
- log.Printf("ReadFile: %s", err)
- p.ServeError(w, r, relpath, err)
- return
- }
- isMarkdown := strings.HasSuffix(abspath, ".md")
+func (p *Presentation) serveHTML(w http.ResponseWriter, r *http.Request, f *file) {
+ src := f.Body
+ isMarkdown := strings.HasSuffix(f.FilePath, ".md")
// if it begins with "<!DOCTYPE " assume it is standalone
// html that doesn't need the template wrapping.
@@ -284,30 +282,24 @@
return
}
- // if it begins with a JSON blob, read in the metadata.
- meta, src, err := extractMetadata(src)
- if err != nil {
- log.Printf("decoding metadata %s: %v", relpath, err)
- }
-
page := Page{
- Title: meta.Title,
- Subtitle: meta.Subtitle,
+ Title: f.Title,
+ Subtitle: f.Subtitle,
GoogleCN: p.googleCN(r),
}
// evaluate as template if indicated
- if meta.Template {
+ if f.Template {
tmpl, err := template.New("main").Funcs(p.TemplateFuncs()).Parse(string(src))
if err != nil {
- log.Printf("parsing template %s: %v", relpath, err)
- p.ServeError(w, r, relpath, err)
+ log.Printf("parsing template %s: %v", f.Path, err)
+ p.ServeError(w, r, f.Path, err)
return
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, page); err != nil {
- log.Printf("executing template %s: %v", relpath, err)
- p.ServeError(w, r, relpath, err)
+ log.Printf("executing template %s: %v", f.Path, err)
+ p.ServeError(w, r, f.Path, err)
return
}
src = buf.Bytes()
@@ -318,15 +310,15 @@
if isMarkdown {
html, err := renderMarkdown(src)
if err != nil {
- log.Printf("executing markdown %s: %v", relpath, err)
- p.ServeError(w, r, relpath, err)
+ log.Printf("executing markdown %s: %v", f.Path, err)
+ p.ServeError(w, r, f.Path, err)
return
}
src = html
}
// if it's the language spec, add tags to EBNF productions
- if strings.HasSuffix(abspath, "go_spec.html") {
+ if strings.HasSuffix(f.FilePath, "go_spec.html") {
var buf bytes.Buffer
spec.Linkify(&buf, src)
src = buf.Bytes()
@@ -350,36 +342,26 @@
// Check to see if we need to redirect or serve another file.
abspath := r.URL.Path
- if m := p.Corpus.MetadataFor(abspath); m != nil {
- if m.Path != abspath {
+ if f := open(p.fs, abspath); f != nil {
+ if f.Path != abspath {
// Redirect to canonical path.
- http.Redirect(w, r, m.Path, http.StatusMovedPermanently)
+ http.Redirect(w, r, f.Path, http.StatusMovedPermanently)
return
}
// Serve from the actual filesystem path.
- p.ServeHTMLDoc(w, r, m.FilePath, m.Path)
+ p.serveHTML(w, r, f)
return
}
relpath := abspath[1:] // strip leading slash
- switch path.Ext(relpath) {
- case ".html":
- p.ServeHTMLDoc(w, r, abspath, relpath)
- return
-
- case ".go":
- p.serveTextFile(w, r, abspath, relpath, "Source file")
- return
- }
-
- dir, err := fs.Stat(p.Corpus.fs, toFS(abspath))
+ dir, err := fs.Stat(p.fs, toFS(abspath))
if err != nil {
// Check for spurious trailing slash.
if strings.HasSuffix(abspath, "/") {
trimmed := abspath[:len(abspath)-1]
- if _, err := fs.Stat(p.Corpus.fs, toFS(trimmed)); err == nil ||
- p.Corpus.MetadataFor(trimmed) != nil {
+ if _, err := fs.Stat(p.fs, toFS(trimmed)); err == nil ||
+ open(p.fs, trimmed) != nil {
http.Redirect(w, r, trimmed, http.StatusMovedPermanently)
return
}
@@ -393,20 +375,15 @@
if redirect(w, r) {
return
}
- index := path.Join(fsPath, "index.html")
- if isTextFile(p.Corpus.fs, index) || isTextFile(p.Corpus.fs, path.Join(fsPath, "index.md")) {
- p.ServeHTMLDoc(w, r, index, index)
- return
- }
p.serveDirectory(w, r, abspath, relpath)
return
}
- if isTextFile(p.Corpus.fs, fsPath) {
+ if isTextFile(p.fs, fsPath) {
if redirectFile(w, r) {
return
}
- p.serveTextFile(w, r, abspath, relpath, "Text file")
+ p.serveTextFile(w, r, abspath, relpath)
return
}
diff --git a/internal/godoc/server_test.go b/internal/godoc/server_test.go
index 57d61e9..152e934 100644
--- a/internal/godoc/server_test.go
+++ b/internal/godoc/server_test.go
@@ -29,11 +29,11 @@
}
func TestRedirectAndMetadata(t *testing.T) {
- c := NewCorpus(fstest.MapFS{
+ fsys := fstest.MapFS{
"doc/x/index.html": {Data: []byte("Hello, x.")},
- })
+ }
p := &Presentation{
- Corpus: c,
+ fs: fsys,
GodocHTML: template.Must(template.New("").Parse(`{{printf "%s" .Body}}`)),
}
@@ -54,10 +54,10 @@
func TestMarkdown(t *testing.T) {
p := &Presentation{
- Corpus: NewCorpus(fstest.MapFS{
+ fs: fstest.MapFS{
"doc/test.md": {Data: []byte("**bold**")},
"doc/test2.md": {Data: []byte(`{{"*template*"}}`)},
- }),
+ },
GodocHTML: template.Must(template.New("").Parse(`{{printf "%s" .Body}}`)),
}
diff --git a/internal/godoc/template.go b/internal/godoc/template.go
index 5baa140..138b71f 100644
--- a/internal/godoc/template.go
+++ b/internal/godoc/template.go
@@ -50,8 +50,8 @@
// contents reads and returns the content of the named file
// (from the virtual file system, so for example /doc refers to $GOROOT/doc).
-func (c *Corpus) contents(name string) string {
- file, err := fs.ReadFile(c.fs, toFS(name))
+func (p *Presentation) contents(name string) string {
+ file, err := fs.ReadFile(p.fs, toFS(name))
if err != nil {
log.Panic(err)
}
@@ -81,7 +81,7 @@
}
}()
- text := p.Corpus.contents(file)
+ text := p.contents(file)
var command string
switch len(arg) {
case 0:
@@ -89,10 +89,10 @@
command = fmt.Sprintf("code %q", file)
case 1:
command = fmt.Sprintf("code %q %s", file, stringFor(arg[0]))
- text = p.Corpus.oneLine(file, text, arg[0])
+ text = p.oneLine(file, text, arg[0])
case 2:
command = fmt.Sprintf("code %q %s %s", file, stringFor(arg[0]), stringFor(arg[1]))
- text = p.Corpus.multipleLines(file, text, arg[0], arg[1])
+ text = p.multipleLines(file, text, arg[0], arg[1])
default:
return "", fmt.Errorf("incorrect code invocation: code %q [%v, ...] (%d arguments)", file, arg[0], len(arg))
}
@@ -124,8 +124,8 @@
}
// oneLine returns the single line generated by a two-argument code invocation.
-func (c *Corpus) oneLine(file, text string, arg interface{}) string {
- lines := strings.SplitAfter(c.contents(file), "\n")
+func (p *Presentation) oneLine(file, text string, arg interface{}) string {
+ lines := strings.SplitAfter(p.contents(file), "\n")
line, pattern, isInt := parseArg(arg, file, len(lines))
if isInt {
return lines[line-1]
@@ -134,8 +134,8 @@
}
// multipleLines returns the text generated by a three-argument code invocation.
-func (c *Corpus) multipleLines(file, text string, arg1, arg2 interface{}) string {
- lines := strings.SplitAfter(c.contents(file), "\n")
+func (p *Presentation) multipleLines(file, text string, arg1, arg2 interface{}) string {
+ lines := strings.SplitAfter(p.contents(file), "\n")
line1, pattern1, isInt1 := parseArg(arg1, file, len(lines))
line2, pattern2, isInt2 := parseArg(arg2, file, len(lines))
if !isInt1 {
diff --git a/internal/godoc/versions.go b/internal/godoc/versions.go
deleted file mode 100644
index 9f18fb4..0000000
--- a/internal/godoc/versions.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2018 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.
-
-//go:build go1.16
-// +build go1.16
-
-// This file caches information about which standard library types, methods,
-// and functions appeared in what version of Go
-
-package godoc
-
-import (
- "log"
-
- "golang.org/x/website/internal/api"
-)
-
-// InitVersionInfo parses the $GOROOT/api/go*.txt API definition files to discover
-// which API features were added in which Go releases.
-func (c *Corpus) InitVersionInfo() {
- var err error
- c.pkgAPIInfo, err = api.Load()
- if err != nil {
- // TODO: consider making this fatal, after the Go 1.11 cycle.
- log.Printf("godoc: error parsing API version files: %v", err)
- }
-}