Bumping k8s dependencies to 1.13
This commit is contained in:
2
vendor/golang.org/x/tools/godoc/analysis/README
generated
vendored
2
vendor/golang.org/x/tools/godoc/analysis/README
generated
vendored
@@ -49,7 +49,7 @@ CALLEES:
|
||||
|
||||
Type info:
|
||||
- In the source viewer's lower pane, use a toggle div around the
|
||||
IMPLEMENTS and METHODSETS lists, like we do in the pacakge view.
|
||||
IMPLEMENTS and METHODSETS lists, like we do in the package view.
|
||||
Only expand them initially if short.
|
||||
- Include IMPLEMENTS and METHOD SETS information in search index.
|
||||
- URLs in IMPLEMENTS/METHOD SETS always link to source, even from the
|
||||
|
13
vendor/golang.org/x/tools/godoc/appengine.go
generated
vendored
13
vendor/golang.org/x/tools/godoc/appengine.go
generated
vendored
@@ -1,13 +0,0 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package godoc
|
||||
|
||||
import "google.golang.org/appengine"
|
||||
|
||||
func init() {
|
||||
onAppengine = !appengine.IsDevAppServer()
|
||||
}
|
217
vendor/golang.org/x/tools/godoc/cmdline.go
generated
vendored
217
vendor/golang.org/x/tools/godoc/cmdline.go
generated
vendored
@@ -1,217 +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.
|
||||
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/godoc/vfs"
|
||||
)
|
||||
|
||||
const (
|
||||
target = "/target"
|
||||
cmdPrefix = "cmd/"
|
||||
srcPrefix = "src/"
|
||||
toolsPath = "golang.org/x/tools/cmd/"
|
||||
)
|
||||
|
||||
// CommandLine returns godoc results to w.
|
||||
// Note that it may add a /target path to fs.
|
||||
func CommandLine(w io.Writer, fs vfs.NameSpace, pres *Presentation, args []string) error {
|
||||
path := args[0]
|
||||
srcMode := pres.SrcMode
|
||||
cmdMode := strings.HasPrefix(path, cmdPrefix)
|
||||
if strings.HasPrefix(path, srcPrefix) {
|
||||
path = strings.TrimPrefix(path, srcPrefix)
|
||||
srcMode = true
|
||||
}
|
||||
var abspath, relpath string
|
||||
if cmdMode {
|
||||
path = strings.TrimPrefix(path, cmdPrefix)
|
||||
} else {
|
||||
abspath, relpath = paths(fs, pres, path)
|
||||
}
|
||||
|
||||
var mode PageInfoMode
|
||||
if relpath == builtinPkgPath {
|
||||
// the fake built-in package contains unexported identifiers
|
||||
mode = NoFiltering | NoTypeAssoc
|
||||
}
|
||||
if pres.AllMode {
|
||||
mode |= NoFiltering
|
||||
}
|
||||
if srcMode {
|
||||
// only filter exports if we don't have explicit command-line filter arguments
|
||||
if len(args) > 1 {
|
||||
mode |= NoFiltering
|
||||
}
|
||||
mode |= ShowSource
|
||||
}
|
||||
|
||||
// First, try as package unless forced as command.
|
||||
var info *PageInfo
|
||||
if !cmdMode {
|
||||
info = pres.GetPkgPageInfo(abspath, relpath, mode)
|
||||
}
|
||||
|
||||
// Second, try as command (if the path is not absolute).
|
||||
var cinfo *PageInfo
|
||||
if !filepath.IsAbs(path) {
|
||||
// First try go.tools/cmd.
|
||||
abspath = pathpkg.Join(pres.PkgFSRoot(), toolsPath+path)
|
||||
cinfo = pres.GetCmdPageInfo(abspath, relpath, mode)
|
||||
if cinfo.IsEmpty() {
|
||||
// Then try $GOROOT/src/cmd.
|
||||
abspath = pathpkg.Join(pres.CmdFSRoot(), cmdPrefix, path)
|
||||
cinfo = pres.GetCmdPageInfo(abspath, relpath, mode)
|
||||
}
|
||||
}
|
||||
|
||||
// determine what to use
|
||||
if info == nil || info.IsEmpty() {
|
||||
if cinfo != nil && !cinfo.IsEmpty() {
|
||||
// only cinfo exists - switch to cinfo
|
||||
info = cinfo
|
||||
}
|
||||
} else if cinfo != nil && !cinfo.IsEmpty() {
|
||||
// both info and cinfo exist - use cinfo if info
|
||||
// contains only subdirectory information
|
||||
if info.PAst == nil && info.PDoc == nil {
|
||||
info = cinfo
|
||||
} else if relpath != target {
|
||||
// The above check handles the case where an operating system path
|
||||
// is provided (see documentation for paths below). In that case,
|
||||
// relpath is set to "/target" (in anticipation of accessing packages there),
|
||||
// and is therefore not expected to match a command.
|
||||
fmt.Fprintf(w, "use 'godoc %s%s' for documentation on the %s command \n\n", cmdPrefix, relpath, relpath)
|
||||
}
|
||||
}
|
||||
|
||||
if info == nil {
|
||||
return fmt.Errorf("%s: no such directory or package", args[0])
|
||||
}
|
||||
if info.Err != nil {
|
||||
return info.Err
|
||||
}
|
||||
|
||||
if info.PDoc != nil && info.PDoc.ImportPath == target {
|
||||
// Replace virtual /target with actual argument from command line.
|
||||
info.PDoc.ImportPath = args[0]
|
||||
}
|
||||
|
||||
// If we have more than one argument, use the remaining arguments for filtering.
|
||||
if len(args) > 1 {
|
||||
info.IsFiltered = true
|
||||
filterInfo(args[1:], info)
|
||||
}
|
||||
|
||||
packageText := pres.PackageText
|
||||
if pres.HTMLMode {
|
||||
packageText = pres.PackageHTML
|
||||
}
|
||||
if err := packageText.Execute(w, info); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// paths determines the paths to use.
|
||||
//
|
||||
// If we are passed an operating system path like . or ./foo or /foo/bar or c:\mysrc,
|
||||
// we need to map that path somewhere in the fs name space so that routines
|
||||
// like getPageInfo will see it. We use the arbitrarily-chosen virtual path "/target"
|
||||
// for this. That is, if we get passed a directory like the above, we map that
|
||||
// directory so that getPageInfo sees it as /target.
|
||||
// Returns the absolute and relative paths.
|
||||
func paths(fs vfs.NameSpace, pres *Presentation, path string) (abspath, relpath string) {
|
||||
if filepath.IsAbs(path) {
|
||||
fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
|
||||
return target, target
|
||||
}
|
||||
if build.IsLocalImport(path) {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Printf("error while getting working directory: %v", err)
|
||||
}
|
||||
path = filepath.Join(cwd, path)
|
||||
fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
|
||||
return target, target
|
||||
}
|
||||
bp, err := build.Import(path, "", build.FindOnly)
|
||||
if err != nil {
|
||||
log.Printf("error while importing build package: %v", err)
|
||||
}
|
||||
if bp.Dir != "" && bp.ImportPath != "" {
|
||||
fs.Bind(target, vfs.OS(bp.Dir), "/", vfs.BindReplace)
|
||||
return target, bp.ImportPath
|
||||
}
|
||||
return pathpkg.Join(pres.PkgFSRoot(), path), path
|
||||
}
|
||||
|
||||
// filterInfo updates info to include only the nodes that match the given
|
||||
// filter args.
|
||||
func filterInfo(args []string, info *PageInfo) {
|
||||
rx, err := makeRx(args)
|
||||
if err != nil {
|
||||
log.Fatalf("illegal regular expression from %v: %v", args, err)
|
||||
}
|
||||
|
||||
filter := func(s string) bool { return rx.MatchString(s) }
|
||||
switch {
|
||||
case info.PAst != nil:
|
||||
newPAst := map[string]*ast.File{}
|
||||
for name, a := range info.PAst {
|
||||
cmap := ast.NewCommentMap(info.FSet, a, a.Comments)
|
||||
a.Comments = []*ast.CommentGroup{} // remove all comments.
|
||||
ast.FilterFile(a, filter)
|
||||
if len(a.Decls) > 0 {
|
||||
newPAst[name] = a
|
||||
}
|
||||
for _, d := range a.Decls {
|
||||
// add back the comments associated with d only
|
||||
comments := cmap.Filter(d).Comments()
|
||||
a.Comments = append(a.Comments, comments...)
|
||||
}
|
||||
}
|
||||
info.PAst = newPAst // add only matching files.
|
||||
case info.PDoc != nil:
|
||||
info.PDoc.Filter(filter)
|
||||
}
|
||||
}
|
||||
|
||||
// Does s look like a regular expression?
|
||||
func isRegexp(s string) bool {
|
||||
return strings.ContainsAny(s, ".(|)*+?^$[]")
|
||||
}
|
||||
|
||||
// Make a regular expression of the form
|
||||
// names[0]|names[1]|...names[len(names)-1].
|
||||
// Returns an error if the regular expression is illegal.
|
||||
func makeRx(names []string) (*regexp.Regexp, error) {
|
||||
if len(names) == 0 {
|
||||
return nil, fmt.Errorf("no expression provided")
|
||||
}
|
||||
s := ""
|
||||
for i, name := range names {
|
||||
if i > 0 {
|
||||
s += "|"
|
||||
}
|
||||
if isRegexp(name) {
|
||||
s += name
|
||||
} else {
|
||||
s += "^" + name + "$" // must match exactly
|
||||
}
|
||||
}
|
||||
return regexp.Compile(s)
|
||||
}
|
312
vendor/golang.org/x/tools/godoc/cmdline_test.go
generated
vendored
312
vendor/golang.org/x/tools/godoc/cmdline_test.go
generated
vendored
@@ -1,312 +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.
|
||||
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"golang.org/x/tools/godoc/vfs"
|
||||
"golang.org/x/tools/godoc/vfs/mapfs"
|
||||
)
|
||||
|
||||
// setupGoroot creates temporary directory to act as GOROOT when running tests
|
||||
// that depend upon the build package. It updates build.Default to point to the
|
||||
// new GOROOT.
|
||||
// It returns a function that can be called to reset build.Default and remove
|
||||
// the temporary directory.
|
||||
func setupGoroot(t *testing.T) (cleanup func()) {
|
||||
var stdLib = map[string]string{
|
||||
"src/fmt/fmt.go": `// Package fmt implements formatted I/O.
|
||||
package fmt
|
||||
|
||||
type Stringer interface {
|
||||
String() string
|
||||
}
|
||||
`,
|
||||
}
|
||||
goroot, err := ioutil.TempDir("", "cmdline_test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
origContext := build.Default
|
||||
build.Default = build.Context{
|
||||
GOROOT: goroot,
|
||||
Compiler: "gc",
|
||||
}
|
||||
for relname, contents := range stdLib {
|
||||
name := filepath.Join(goroot, relname)
|
||||
if err := os.MkdirAll(filepath.Dir(name), 0770); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(name, []byte(contents), 0770); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
return func() {
|
||||
if err := os.RemoveAll(goroot); err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
build.Default = origContext
|
||||
}
|
||||
}
|
||||
|
||||
func TestPaths(t *testing.T) {
|
||||
cleanup := setupGoroot(t)
|
||||
defer cleanup()
|
||||
|
||||
pres := &Presentation{
|
||||
pkgHandler: handlerServer{
|
||||
fsRoot: "/fsroot",
|
||||
},
|
||||
}
|
||||
fs := make(vfs.NameSpace)
|
||||
|
||||
absPath := "/foo/fmt"
|
||||
if runtime.GOOS == "windows" {
|
||||
absPath = `c:\foo\fmt`
|
||||
}
|
||||
|
||||
for _, tc := range []struct {
|
||||
desc string
|
||||
path string
|
||||
expAbs string
|
||||
expRel string
|
||||
}{
|
||||
{
|
||||
"Absolute path",
|
||||
absPath,
|
||||
"/target",
|
||||
"/target",
|
||||
},
|
||||
{
|
||||
"Local import",
|
||||
"../foo/fmt",
|
||||
"/target",
|
||||
"/target",
|
||||
},
|
||||
{
|
||||
"Import",
|
||||
"fmt",
|
||||
"/target",
|
||||
"fmt",
|
||||
},
|
||||
{
|
||||
"Default",
|
||||
"unknownpkg",
|
||||
"/fsroot/unknownpkg",
|
||||
"unknownpkg",
|
||||
},
|
||||
} {
|
||||
abs, rel := paths(fs, pres, tc.path)
|
||||
if abs != tc.expAbs || rel != tc.expRel {
|
||||
t.Errorf("%s: paths(%q) = %s,%s; want %s,%s", tc.desc, tc.path, abs, rel, tc.expAbs, tc.expRel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeRx(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
desc string
|
||||
names []string
|
||||
exp string
|
||||
}{
|
||||
{
|
||||
desc: "empty string",
|
||||
names: []string{""},
|
||||
exp: `^$`,
|
||||
},
|
||||
{
|
||||
desc: "simple text",
|
||||
names: []string{"a"},
|
||||
exp: `^a$`,
|
||||
},
|
||||
{
|
||||
desc: "two words",
|
||||
names: []string{"foo", "bar"},
|
||||
exp: `^foo$|^bar$`,
|
||||
},
|
||||
{
|
||||
desc: "word & non-trivial",
|
||||
names: []string{"foo", `ab?c`},
|
||||
exp: `^foo$|ab?c`,
|
||||
},
|
||||
{
|
||||
desc: "bad regexp",
|
||||
names: []string{`(."`},
|
||||
exp: `(."`,
|
||||
},
|
||||
} {
|
||||
expRE, expErr := regexp.Compile(tc.exp)
|
||||
if re, err := makeRx(tc.names); !reflect.DeepEqual(err, expErr) && !reflect.DeepEqual(re, expRE) {
|
||||
t.Errorf("%s: makeRx(%v) = %q,%q; want %q,%q", tc.desc, tc.names, re, err, expRE, expErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandLine(t *testing.T) {
|
||||
cleanup := setupGoroot(t)
|
||||
defer cleanup()
|
||||
mfs := mapfs.New(map[string]string{
|
||||
"src/bar/bar.go": `// Package bar is an example.
|
||||
package bar
|
||||
`,
|
||||
"src/foo/foo.go": `// Package foo.
|
||||
package foo
|
||||
|
||||
// First function is first.
|
||||
func First() {
|
||||
}
|
||||
|
||||
// Second function is second.
|
||||
func Second() {
|
||||
}
|
||||
|
||||
// unexported function is third.
|
||||
func unexported() {
|
||||
}
|
||||
`,
|
||||
"src/gen/gen.go": `// Package gen
|
||||
package gen
|
||||
|
||||
//line notgen.go:3
|
||||
// F doc //line 1 should appear
|
||||
// line 2 should appear
|
||||
func F()
|
||||
//line foo.go:100`, // no newline on end to check corner cases!
|
||||
"src/vet/vet.go": `// Package vet
|
||||
package vet
|
||||
`,
|
||||
"src/cmd/go/doc.go": `// The go command
|
||||
package main
|
||||
`,
|
||||
"src/cmd/gofmt/doc.go": `// The gofmt command
|
||||
package main
|
||||
`,
|
||||
"src/cmd/vet/vet.go": `// The vet command
|
||||
package main
|
||||
`,
|
||||
})
|
||||
fs := make(vfs.NameSpace)
|
||||
fs.Bind("/", mfs, "/", vfs.BindReplace)
|
||||
c := NewCorpus(fs)
|
||||
p := &Presentation{Corpus: c}
|
||||
p.cmdHandler = handlerServer{
|
||||
p: p,
|
||||
c: c,
|
||||
pattern: "/cmd/",
|
||||
fsRoot: "/src",
|
||||
}
|
||||
p.pkgHandler = handlerServer{
|
||||
p: p,
|
||||
c: c,
|
||||
pattern: "/pkg/",
|
||||
fsRoot: "/src",
|
||||
exclude: []string{"/src/cmd"},
|
||||
}
|
||||
p.initFuncMap()
|
||||
p.PackageText = template.Must(template.New("PackageText").Funcs(p.FuncMap()).Parse(`{{$info := .}}{{$filtered := .IsFiltered}}{{if $filtered}}{{range .PAst}}{{range .Decls}}{{node $info .}}{{end}}{{end}}{{else}}{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}:
|
||||
{{node $ $ast}}{{end}}{{end}}{{end}}{{with .PDoc}}{{if $.IsMain}}COMMAND {{.Doc}}{{else}}PACKAGE {{.Doc}}{{end}}{{with .Funcs}}
|
||||
{{range .}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}{{end}}{{end}}{{end}}`))
|
||||
|
||||
for _, tc := range []struct {
|
||||
desc string
|
||||
args []string
|
||||
all bool
|
||||
exp string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
desc: "standard package",
|
||||
args: []string{"fmt"},
|
||||
exp: "PACKAGE Package fmt implements formatted I/O.\n",
|
||||
},
|
||||
{
|
||||
desc: "package",
|
||||
args: []string{"bar"},
|
||||
exp: "PACKAGE Package bar is an example.\n",
|
||||
},
|
||||
{
|
||||
desc: "package w. filter",
|
||||
args: []string{"foo", "First"},
|
||||
exp: "PACKAGE \nfunc First()\n First function is first.\n",
|
||||
},
|
||||
{
|
||||
desc: "package w. bad filter",
|
||||
args: []string{"foo", "DNE"},
|
||||
exp: "PACKAGE ",
|
||||
},
|
||||
{
|
||||
desc: "source mode",
|
||||
args: []string{"src/bar"},
|
||||
exp: "bar/bar.go:\n// Package bar is an example.\npackage bar\n",
|
||||
},
|
||||
{
|
||||
desc: "source mode w. filter",
|
||||
args: []string{"src/foo", "Second"},
|
||||
exp: "// Second function is second.\nfunc Second() {\n}",
|
||||
},
|
||||
{
|
||||
desc: "package w. unexported filter",
|
||||
args: []string{"foo", "unexported"},
|
||||
all: true,
|
||||
exp: "PACKAGE \nfunc unexported()\n unexported function is third.\n",
|
||||
},
|
||||
{
|
||||
desc: "package w. unexported filter",
|
||||
args: []string{"foo", "unexported"},
|
||||
all: false,
|
||||
exp: "PACKAGE ",
|
||||
},
|
||||
{
|
||||
desc: "package w. //line comments",
|
||||
args: []string{"gen", "F"},
|
||||
exp: "PACKAGE \nfunc F()\n F doc //line 1 should appear line 2 should appear\n",
|
||||
},
|
||||
{
|
||||
desc: "command",
|
||||
args: []string{"go"},
|
||||
exp: "COMMAND The go command\n",
|
||||
},
|
||||
{
|
||||
desc: "forced command",
|
||||
args: []string{"cmd/gofmt"},
|
||||
exp: "COMMAND The gofmt command\n",
|
||||
},
|
||||
{
|
||||
desc: "bad arg",
|
||||
args: []string{"doesnotexist"},
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
desc: "both command and package",
|
||||
args: []string{"vet"},
|
||||
exp: "use 'godoc cmd/vet' for documentation on the vet command \n\nPACKAGE Package vet\n",
|
||||
},
|
||||
{
|
||||
desc: "root directory",
|
||||
args: []string{"/"},
|
||||
exp: "",
|
||||
},
|
||||
} {
|
||||
p.AllMode = tc.all
|
||||
w := new(bytes.Buffer)
|
||||
err := CommandLine(w, fs, p, tc.args)
|
||||
if got, want := w.String(), tc.exp; got != want || tc.err == (err == nil) {
|
||||
t.Errorf("%s: CommandLine(%v), All(%v) = %q (%v); want %q (%v)",
|
||||
tc.desc, tc.args, tc.all, got, err, want, tc.err)
|
||||
}
|
||||
}
|
||||
}
|
4
vendor/golang.org/x/tools/godoc/corpus.go
generated
vendored
4
vendor/golang.org/x/tools/godoc/corpus.go
generated
vendored
@@ -108,6 +108,10 @@ type Corpus struct {
|
||||
// flag to check whether a corpus is initialized or not
|
||||
initMu sync.RWMutex
|
||||
initDone bool
|
||||
|
||||
// pkgAPIInfo contains the information about which package API
|
||||
// features were added in which version of Go.
|
||||
pkgAPIInfo apiVersions
|
||||
}
|
||||
|
||||
// NewCorpus returns a new Corpus from a filesystem.
|
||||
|
221
vendor/golang.org/x/tools/godoc/dl/dl.go
generated
vendored
221
vendor/golang.org/x/tools/godoc/dl/dl.go
generated
vendored
@@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
// Package dl implements a simple downloads frontend server.
|
||||
//
|
||||
// It accepts HTTP POST requests to create a new download metadata entity, and
|
||||
@@ -12,25 +10,13 @@
|
||||
package dl
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/datastore"
|
||||
"google.golang.org/appengine/log"
|
||||
"google.golang.org/appengine/memcache"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -39,13 +25,6 @@ const (
|
||||
cacheDuration = time.Hour
|
||||
)
|
||||
|
||||
func RegisterHandlers(mux *http.ServeMux) {
|
||||
mux.Handle("/dl", http.RedirectHandler("/dl/", http.StatusFound))
|
||||
mux.HandleFunc("/dl/", getHandler) // also serves listHandler
|
||||
mux.HandleFunc("/dl/upload", uploadHandler)
|
||||
mux.HandleFunc("/dl/init", initHandler)
|
||||
}
|
||||
|
||||
// File represents a file on the golang.org downloads page.
|
||||
// It should be kept in sync with the upload code in x/build/cmd/release.
|
||||
type File struct {
|
||||
@@ -160,12 +139,12 @@ type Feature struct {
|
||||
var featuredFiles = []Feature{
|
||||
{
|
||||
Platform: "Microsoft Windows",
|
||||
Requirements: "Windows XP SP3 or later, Intel 64-bit processor",
|
||||
Requirements: "Windows 7 or later, Intel 64-bit processor",
|
||||
fileRE: regexp.MustCompile(`\.windows-amd64\.msi$`),
|
||||
},
|
||||
{
|
||||
Platform: "Apple macOS",
|
||||
Requirements: "macOS 10.8 or later, Intel 64-bit processor",
|
||||
Requirements: "macOS 10.10 or later, Intel 64-bit processor",
|
||||
fileRE: regexp.MustCompile(`\.darwin-amd64(-osx10\.8)?\.pkg$`),
|
||||
},
|
||||
{
|
||||
@@ -190,54 +169,6 @@ var (
|
||||
templateFuncs = template.FuncMap{"pretty": pretty}
|
||||
)
|
||||
|
||||
func listHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
var (
|
||||
c = appengine.NewContext(r)
|
||||
d listTemplateData
|
||||
)
|
||||
if _, err := memcache.Gob.Get(c, cacheKey, &d); err != nil {
|
||||
if err == memcache.ErrCacheMiss {
|
||||
log.Debugf(c, "cache miss")
|
||||
} else {
|
||||
log.Errorf(c, "cache get error: %v", err)
|
||||
}
|
||||
|
||||
var fs []File
|
||||
_, err := datastore.NewQuery("File").Ancestor(rootKey(c)).GetAll(c, &fs)
|
||||
if err != nil {
|
||||
log.Errorf(c, "error listing: %v", err)
|
||||
return
|
||||
}
|
||||
d.Stable, d.Unstable, d.Archive = filesToReleases(fs)
|
||||
if len(d.Stable) > 0 {
|
||||
d.Featured = filesToFeatured(d.Stable[0].Files)
|
||||
}
|
||||
|
||||
item := &memcache.Item{Key: cacheKey, Object: &d, Expiration: cacheDuration}
|
||||
if err := memcache.Gob.Set(c, item); err != nil {
|
||||
log.Errorf(c, "cache set error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if r.URL.Query().Get("mode") == "json" {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetIndent("", " ")
|
||||
if err := enc.Encode(d.Stable); err != nil {
|
||||
log.Errorf(c, "failed rendering JSON for releases: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := listTemplate.ExecuteTemplate(w, "root", d); err != nil {
|
||||
log.Errorf(c, "error executing template: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func filesToFeatured(fs []File) (featured []Feature) {
|
||||
for _, feature := range featuredFiles {
|
||||
for _, file := range fs {
|
||||
@@ -382,104 +313,18 @@ func parseVersion(v string) (maj, min int, tail string) {
|
||||
return
|
||||
}
|
||||
|
||||
func uploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
c := appengine.NewContext(r)
|
||||
|
||||
// Authenticate using a user token (same as gomote).
|
||||
user := r.FormValue("user")
|
||||
if !validUser(user) {
|
||||
http.Error(w, "bad user", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
if r.FormValue("key") != userKey(c, user) {
|
||||
http.Error(w, "bad key", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
var f File
|
||||
defer r.Body.Close()
|
||||
if err := json.NewDecoder(r.Body).Decode(&f); err != nil {
|
||||
log.Errorf(c, "error decoding upload JSON: %v", err)
|
||||
http.Error(w, "Something broke", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if f.Filename == "" {
|
||||
http.Error(w, "Must provide Filename", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if f.Uploaded.IsZero() {
|
||||
f.Uploaded = time.Now()
|
||||
}
|
||||
k := datastore.NewKey(c, "File", f.Filename, 0, rootKey(c))
|
||||
if _, err := datastore.Put(c, k, &f); err != nil {
|
||||
log.Errorf(c, "putting File entity: %v", err)
|
||||
http.Error(w, "could not put File entity", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err := memcache.Delete(c, cacheKey); err != nil {
|
||||
log.Errorf(c, "cache delete error: %v", err)
|
||||
}
|
||||
io.WriteString(w, "OK")
|
||||
}
|
||||
|
||||
func getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
name := strings.TrimPrefix(r.URL.Path, "/dl/")
|
||||
if name == "" {
|
||||
listHandler(w, r)
|
||||
return
|
||||
}
|
||||
if !fileRe.MatchString(name) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, downloadBaseURL+name, http.StatusFound)
|
||||
}
|
||||
|
||||
func validUser(user string) bool {
|
||||
switch user {
|
||||
case "adg", "bradfitz", "cbro", "andybons", "valsorda":
|
||||
case "adg", "bradfitz", "cbro", "andybons", "valsorda", "dmitshur", "katiehockman":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func userKey(c context.Context, user string) string {
|
||||
h := hmac.New(md5.New, []byte(secret(c)))
|
||||
h.Write([]byte("user-" + user))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
var fileRe = regexp.MustCompile(`^go[0-9a-z.]+\.[0-9a-z.-]+\.(tar\.gz|pkg|msi|zip)$`)
|
||||
|
||||
func initHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var fileRoot struct {
|
||||
Root string
|
||||
}
|
||||
c := appengine.NewContext(r)
|
||||
k := rootKey(c)
|
||||
err := datastore.RunInTransaction(c, func(c context.Context) error {
|
||||
err := datastore.Get(c, k, &fileRoot)
|
||||
if err != nil && err != datastore.ErrNoSuchEntity {
|
||||
return err
|
||||
}
|
||||
_, err = datastore.Put(c, k, &fileRoot)
|
||||
return err
|
||||
}, nil)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
io.WriteString(w, "OK")
|
||||
}
|
||||
|
||||
// rootKey is the ancestor of all File entities.
|
||||
func rootKey(c context.Context) *datastore.Key {
|
||||
return datastore.NewKey(c, "FileRoot", "root", 0, nil)
|
||||
}
|
||||
var (
|
||||
fileRe = regexp.MustCompile(`^go[0-9a-z.]+\.[0-9a-z.-]+\.(tar\.gz|pkg|msi|zip)$`)
|
||||
goGetRe = regexp.MustCompile(`^go[0-9a-z.]+\.[0-9a-z.-]+$`)
|
||||
)
|
||||
|
||||
// pretty returns a human-readable version of the given OS, Arch, or Kind.
|
||||
func pretty(s string) string {
|
||||
@@ -505,55 +350,3 @@ var prettyStrings = map[string]string{
|
||||
"installer": "Installer",
|
||||
"source": "Source",
|
||||
}
|
||||
|
||||
// Code below copied from x/build/app/key
|
||||
|
||||
var theKey struct {
|
||||
sync.RWMutex
|
||||
builderKey
|
||||
}
|
||||
|
||||
type builderKey struct {
|
||||
Secret string
|
||||
}
|
||||
|
||||
func (k *builderKey) Key(c context.Context) *datastore.Key {
|
||||
return datastore.NewKey(c, "BuilderKey", "root", 0, nil)
|
||||
}
|
||||
|
||||
func secret(c context.Context) string {
|
||||
// check with rlock
|
||||
theKey.RLock()
|
||||
k := theKey.Secret
|
||||
theKey.RUnlock()
|
||||
if k != "" {
|
||||
return k
|
||||
}
|
||||
|
||||
// prepare to fill; check with lock and keep lock
|
||||
theKey.Lock()
|
||||
defer theKey.Unlock()
|
||||
if theKey.Secret != "" {
|
||||
return theKey.Secret
|
||||
}
|
||||
|
||||
// fill
|
||||
if err := datastore.Get(c, theKey.Key(c), &theKey.builderKey); err != nil {
|
||||
if err == datastore.ErrNoSuchEntity {
|
||||
// If the key is not stored in datastore, write it.
|
||||
// This only happens at the beginning of a new deployment.
|
||||
// The code is left here for SDK use and in case a fresh
|
||||
// deployment is ever needed. "gophers rule" is not the
|
||||
// real key.
|
||||
if !appengine.IsDevAppServer() {
|
||||
panic("lost key from datastore")
|
||||
}
|
||||
theKey.Secret = "gophers rule"
|
||||
datastore.Put(c, theKey.Key(c), &theKey.builderKey)
|
||||
return theKey.Secret
|
||||
}
|
||||
panic("cannot load builder key: " + err.Error())
|
||||
}
|
||||
|
||||
return theKey.Secret
|
||||
}
|
||||
|
2
vendor/golang.org/x/tools/godoc/dl/dl_test.go
generated
vendored
2
vendor/golang.org/x/tools/godoc/dl/dl_test.go
generated
vendored
@@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package dl
|
||||
|
||||
import (
|
||||
|
267
vendor/golang.org/x/tools/godoc/dl/server.go
generated
vendored
Normal file
267
vendor/golang.org/x/tools/godoc/dl/server.go
generated
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build golangorg
|
||||
|
||||
package dl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/datastore"
|
||||
"golang.org/x/tools/godoc/env"
|
||||
"golang.org/x/tools/internal/memcache"
|
||||
)
|
||||
|
||||
type server struct {
|
||||
datastore *datastore.Client
|
||||
memcache *memcache.CodecClient
|
||||
}
|
||||
|
||||
func RegisterHandlers(mux *http.ServeMux, dc *datastore.Client, mc *memcache.Client) {
|
||||
s := server{dc, mc.WithCodec(memcache.Gob)}
|
||||
mux.HandleFunc("/dl", s.getHandler)
|
||||
mux.HandleFunc("/dl/", s.getHandler) // also serves listHandler
|
||||
mux.HandleFunc("/dl/upload", s.uploadHandler)
|
||||
|
||||
// NOTE(cbro): this only needs to be run once per project,
|
||||
// and should be behind an admin login.
|
||||
// TODO(cbro): move into a locally-run program? or remove?
|
||||
// mux.HandleFunc("/dl/init", initHandler)
|
||||
}
|
||||
|
||||
// rootKey is the ancestor of all File entities.
|
||||
var rootKey = datastore.NameKey("FileRoot", "root", nil)
|
||||
|
||||
func (h server) listHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
ctx := r.Context()
|
||||
var d listTemplateData
|
||||
|
||||
if err := h.memcache.Get(ctx, cacheKey, &d); err != nil {
|
||||
if err != memcache.ErrCacheMiss {
|
||||
log.Printf("ERROR cache get error: %v", err)
|
||||
// NOTE(cbro): continue to hit datastore if the memcache is down.
|
||||
}
|
||||
|
||||
var fs []File
|
||||
q := datastore.NewQuery("File").Ancestor(rootKey)
|
||||
if _, err := h.datastore.GetAll(ctx, q, &fs); err != nil {
|
||||
log.Printf("ERROR error listing: %v", err)
|
||||
http.Error(w, "Could not get download page. Try again in a few minutes.", 500)
|
||||
return
|
||||
}
|
||||
d.Stable, d.Unstable, d.Archive = filesToReleases(fs)
|
||||
if len(d.Stable) > 0 {
|
||||
d.Featured = filesToFeatured(d.Stable[0].Files)
|
||||
}
|
||||
|
||||
item := &memcache.Item{Key: cacheKey, Object: &d, Expiration: cacheDuration}
|
||||
if err := h.memcache.Set(ctx, item); err != nil {
|
||||
log.Printf("ERROR cache set error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if r.URL.Query().Get("mode") == "json" {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetIndent("", " ")
|
||||
if err := enc.Encode(d.Stable); err != nil {
|
||||
log.Printf("ERROR rendering JSON for releases: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := listTemplate.ExecuteTemplate(w, "root", d); err != nil {
|
||||
log.Printf("ERROR executing template: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (h server) uploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
ctx := r.Context()
|
||||
|
||||
// Authenticate using a user token (same as gomote).
|
||||
user := r.FormValue("user")
|
||||
if !validUser(user) {
|
||||
http.Error(w, "bad user", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
if r.FormValue("key") != h.userKey(ctx, user) {
|
||||
http.Error(w, "bad key", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
var f File
|
||||
defer r.Body.Close()
|
||||
if err := json.NewDecoder(r.Body).Decode(&f); err != nil {
|
||||
log.Printf("ERROR decoding upload JSON: %v", err)
|
||||
http.Error(w, "Something broke", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if f.Filename == "" {
|
||||
http.Error(w, "Must provide Filename", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if f.Uploaded.IsZero() {
|
||||
f.Uploaded = time.Now()
|
||||
}
|
||||
k := datastore.NameKey("File", f.Filename, rootKey)
|
||||
if _, err := h.datastore.Put(ctx, k, &f); err != nil {
|
||||
log.Printf("ERROR File entity: %v", err)
|
||||
http.Error(w, "could not put File entity", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err := h.memcache.Delete(ctx, cacheKey); err != nil {
|
||||
log.Printf("ERROR delete error: %v", err)
|
||||
}
|
||||
io.WriteString(w, "OK")
|
||||
}
|
||||
|
||||
func (h server) getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// For go get golang.org/dl/go1.x.y, we need to serve the
|
||||
// same meta tags at /dl for cmd/go to validate against /dl/go1.x.y:
|
||||
if r.URL.Path == "/dl" && (r.Method == "GET" || r.Method == "HEAD") && r.FormValue("go-get") == "1" {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
fmt.Fprintf(w, `<!DOCTYPE html><html><head>
|
||||
<meta name="go-import" content="golang.org/dl git https://go.googlesource.com/dl">
|
||||
</head></html>`)
|
||||
return
|
||||
}
|
||||
if r.URL.Path == "/dl" {
|
||||
http.Redirect(w, r, "/dl/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
name := strings.TrimPrefix(r.URL.Path, "/dl/")
|
||||
if name == "" {
|
||||
h.listHandler(w, r)
|
||||
return
|
||||
}
|
||||
if fileRe.MatchString(name) {
|
||||
http.Redirect(w, r, downloadBaseURL+name, http.StatusFound)
|
||||
return
|
||||
}
|
||||
if goGetRe.MatchString(name) {
|
||||
var isGoGet bool
|
||||
if r.Method == "GET" || r.Method == "HEAD" {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
isGoGet = r.FormValue("go-get") == "1"
|
||||
}
|
||||
if !isGoGet {
|
||||
w.Header().Set("Location", "https://golang.org/dl/#"+name)
|
||||
w.WriteHeader(http.StatusFound)
|
||||
}
|
||||
fmt.Fprintf(w, `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta name="go-import" content="golang.org/dl git https://go.googlesource.com/dl">
|
||||
<meta http-equiv="refresh" content="0; url=https://golang.org/dl/#%s">
|
||||
</head>
|
||||
<body>
|
||||
Nothing to see here; <a href="https://golang.org/dl/#%s">move along</a>.
|
||||
</body>
|
||||
</html>
|
||||
`, html.EscapeString(name), html.EscapeString(name))
|
||||
return
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
||||
func (h server) initHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var fileRoot struct {
|
||||
Root string
|
||||
}
|
||||
ctx := r.Context()
|
||||
k := rootKey
|
||||
_, err := h.datastore.RunInTransaction(ctx, func(tx *datastore.Transaction) error {
|
||||
err := tx.Get(k, &fileRoot)
|
||||
if err != nil && err != datastore.ErrNoSuchEntity {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Put(k, &fileRoot)
|
||||
return err
|
||||
}, nil)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
io.WriteString(w, "OK")
|
||||
}
|
||||
|
||||
func (h server) userKey(c context.Context, user string) string {
|
||||
hash := hmac.New(md5.New, []byte(h.secret(c)))
|
||||
hash.Write([]byte("user-" + user))
|
||||
return fmt.Sprintf("%x", hash.Sum(nil))
|
||||
}
|
||||
|
||||
// Code below copied from x/build/app/key
|
||||
|
||||
var theKey struct {
|
||||
sync.RWMutex
|
||||
builderKey
|
||||
}
|
||||
|
||||
type builderKey struct {
|
||||
Secret string
|
||||
}
|
||||
|
||||
func (k *builderKey) Key() *datastore.Key {
|
||||
return datastore.NameKey("BuilderKey", "root", nil)
|
||||
}
|
||||
|
||||
func (h server) secret(ctx context.Context) string {
|
||||
// check with rlock
|
||||
theKey.RLock()
|
||||
k := theKey.Secret
|
||||
theKey.RUnlock()
|
||||
if k != "" {
|
||||
return k
|
||||
}
|
||||
|
||||
// prepare to fill; check with lock and keep lock
|
||||
theKey.Lock()
|
||||
defer theKey.Unlock()
|
||||
if theKey.Secret != "" {
|
||||
return theKey.Secret
|
||||
}
|
||||
|
||||
// fill
|
||||
if err := h.datastore.Get(ctx, theKey.Key(), &theKey.builderKey); err != nil {
|
||||
if err == datastore.ErrNoSuchEntity {
|
||||
// If the key is not stored in datastore, write it.
|
||||
// This only happens at the beginning of a new deployment.
|
||||
// The code is left here for SDK use and in case a fresh
|
||||
// deployment is ever needed. "gophers rule" is not the
|
||||
// real key.
|
||||
if env.IsProd() {
|
||||
panic("lost key from datastore")
|
||||
}
|
||||
theKey.Secret = "gophers rule"
|
||||
h.datastore.Put(ctx, theKey.Key(), &theKey.builderKey)
|
||||
return theKey.Secret
|
||||
}
|
||||
panic("cannot load builder key: " + err.Error())
|
||||
}
|
||||
|
||||
return theKey.Secret
|
||||
}
|
4
vendor/golang.org/x/tools/godoc/dl/tmpl.go
generated
vendored
4
vendor/golang.org/x/tools/godoc/dl/tmpl.go
generated
vendored
@@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package dl
|
||||
|
||||
// TODO(adg): refactor this to use the tools/godoc/static template.
|
||||
@@ -220,7 +218,7 @@ $(document).ready(function() {
|
||||
<p>This is an <b>unstable</b> version of Go. Use with caution.</p>
|
||||
<p>If you already have Go installed, you can install this version by running:</p>
|
||||
<pre>
|
||||
go get golang.org/x/build/version/{{.Version}}
|
||||
go get golang.org/dl/{{.Version}}
|
||||
</pre>
|
||||
<p>Then, use the <code>{{.Version}}</code> command instead of the <code>go</code> command to use {{.Version}}.</p>
|
||||
{{end}}
|
||||
|
41
vendor/golang.org/x/tools/godoc/env/env.go
generated
vendored
Normal file
41
vendor/golang.org/x/tools/godoc/env/env.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
// 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.
|
||||
|
||||
// Package env provides environment information for the godoc server running on
|
||||
// golang.org.
|
||||
package env
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
isProd = boolEnv("GODOC_PROD")
|
||||
enforceHosts = boolEnv("GODOC_ENFORCE_HOSTS")
|
||||
)
|
||||
|
||||
// IsProd reports whether the server is running in its production configuration
|
||||
// on golang.org.
|
||||
func IsProd() bool {
|
||||
return isProd
|
||||
}
|
||||
|
||||
// EnforceHosts reports whether host filtering should be enforced.
|
||||
func EnforceHosts() bool {
|
||||
return enforceHosts
|
||||
}
|
||||
|
||||
func boolEnv(key string) bool {
|
||||
v := os.Getenv(key)
|
||||
if v == "" {
|
||||
return false
|
||||
}
|
||||
b, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
log.Fatalf("environment variable %s (%q) must be a boolean", key, v)
|
||||
}
|
||||
return b
|
||||
}
|
167
vendor/golang.org/x/tools/godoc/godoc.go
generated
vendored
167
vendor/golang.org/x/tools/godoc/godoc.go
generated
vendored
@@ -10,6 +10,7 @@
|
||||
package godoc // import "golang.org/x/tools/godoc"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
@@ -61,6 +62,7 @@ func (p *Presentation) initFuncMap() {
|
||||
// various helpers
|
||||
"filename": filenameFunc,
|
||||
"repeat": strings.Repeat,
|
||||
"since": p.Corpus.pkgAPIInfo.sinceVersionFunc,
|
||||
|
||||
// access to FileInfos (directory listings)
|
||||
"fileInfoName": fileInfoNameFunc,
|
||||
@@ -75,7 +77,6 @@ func (p *Presentation) initFuncMap() {
|
||||
"node": p.nodeFunc,
|
||||
"node_html": p.node_htmlFunc,
|
||||
"comment_html": comment_htmlFunc,
|
||||
"comment_text": comment_textFunc,
|
||||
"sanitize": sanitizeFunc,
|
||||
|
||||
// support for URL attributes
|
||||
@@ -89,7 +90,6 @@ func (p *Presentation) initFuncMap() {
|
||||
|
||||
// formatting of Examples
|
||||
"example_html": p.example_htmlFunc,
|
||||
"example_text": p.example_textFunc,
|
||||
"example_name": p.example_nameFunc,
|
||||
"example_suffix": p.example_suffixFunc,
|
||||
|
||||
@@ -109,6 +109,9 @@ func (p *Presentation) initFuncMap() {
|
||||
|
||||
// check whether to display third party section or not
|
||||
"hasThirdParty": hasThirdParty,
|
||||
|
||||
// get the no. of columns to split the toc in search page
|
||||
"tocColCount": tocColCount,
|
||||
}
|
||||
if p.URLForSrc != nil {
|
||||
p.funcMap["srcLink"] = p.URLForSrc
|
||||
@@ -187,13 +190,13 @@ func (p *Presentation) infoSnippet_htmlFunc(info SpotInfo) string {
|
||||
|
||||
func (p *Presentation) nodeFunc(info *PageInfo, node interface{}) string {
|
||||
var buf bytes.Buffer
|
||||
p.writeNode(&buf, info.FSet, node)
|
||||
p.writeNode(&buf, info, info.FSet, node)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (p *Presentation) node_htmlFunc(info *PageInfo, node interface{}, linkify bool) string {
|
||||
var buf1 bytes.Buffer
|
||||
p.writeNode(&buf1, info.FSet, node)
|
||||
p.writeNode(&buf1, info, info.FSet, node)
|
||||
|
||||
var buf2 bytes.Buffer
|
||||
if n, _ := node.(ast.Node); n != nil && linkify && p.DeclLinks {
|
||||
@@ -370,15 +373,6 @@ func containsOnlySpace(buf []byte) bool {
|
||||
return bytes.IndexFunc(buf, isNotSpace) == -1
|
||||
}
|
||||
|
||||
func comment_textFunc(comment, indent, preIndent string) string {
|
||||
var buf bytes.Buffer
|
||||
doc.ToText(&buf, comment, indent, preIndent, punchCardWidth-2*len(indent))
|
||||
if containsOnlySpace(buf.Bytes()) {
|
||||
return ""
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// sanitizeFunc sanitizes the argument src by replacing newlines with
|
||||
// blanks, removing extra blanks, and by removing trailing whitespace
|
||||
// and commas before closing parentheses.
|
||||
@@ -587,50 +581,6 @@ func docLinkFunc(s string, ident string) string {
|
||||
return pathpkg.Clean("/pkg/"+s) + "/#" + ident
|
||||
}
|
||||
|
||||
func (p *Presentation) example_textFunc(info *PageInfo, funcName, indent string) string {
|
||||
if !p.ShowExamples {
|
||||
return ""
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
first := true
|
||||
for _, eg := range info.Examples {
|
||||
name := stripExampleSuffix(eg.Name)
|
||||
if name != funcName {
|
||||
continue
|
||||
}
|
||||
|
||||
if !first {
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
first = false
|
||||
|
||||
// print code
|
||||
cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments}
|
||||
config := &printer.Config{Mode: printer.UseSpaces, Tabwidth: p.TabWidth}
|
||||
var buf1 bytes.Buffer
|
||||
config.Fprint(&buf1, info.FSet, cnode)
|
||||
code := buf1.String()
|
||||
|
||||
// Additional formatting if this is a function body. Unfortunately, we
|
||||
// can't print statements individually because we would lose comments
|
||||
// on later statements.
|
||||
if n := len(code); n >= 2 && code[0] == '{' && code[n-1] == '}' {
|
||||
// remove surrounding braces
|
||||
code = code[1 : n-1]
|
||||
// unindent
|
||||
code = replaceLeadingIndentation(code, strings.Repeat(" ", p.TabWidth), indent)
|
||||
}
|
||||
code = strings.Trim(code, "\n")
|
||||
|
||||
buf.WriteString(indent)
|
||||
buf.WriteString("Example:\n")
|
||||
buf.WriteString(code)
|
||||
buf.WriteString("\n\n")
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (p *Presentation) example_htmlFunc(info *PageInfo, funcName string) string {
|
||||
var buf bytes.Buffer
|
||||
for _, eg := range info.Examples {
|
||||
@@ -664,6 +614,7 @@ func (p *Presentation) example_htmlFunc(info *PageInfo, funcName string) string
|
||||
play := ""
|
||||
if eg.Play != nil && p.ShowPlayground {
|
||||
var buf bytes.Buffer
|
||||
eg.Play.Comments = filterOutBuildAnnotations(eg.Play.Comments)
|
||||
if err := format.Node(&buf, info.FSet, eg.Play); err != nil {
|
||||
log.Print(err)
|
||||
} else {
|
||||
@@ -692,6 +643,23 @@ func (p *Presentation) example_htmlFunc(info *PageInfo, funcName string) string
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func filterOutBuildAnnotations(cg []*ast.CommentGroup) []*ast.CommentGroup {
|
||||
if len(cg) == 0 {
|
||||
return cg
|
||||
}
|
||||
|
||||
for i := range cg {
|
||||
if !strings.HasPrefix(cg[i].Text(), "+build ") {
|
||||
// Found the first non-build tag, return from here until the end
|
||||
// of the slice.
|
||||
return cg[i:]
|
||||
}
|
||||
}
|
||||
|
||||
// There weren't any non-build tags, return an empty slice.
|
||||
return []*ast.CommentGroup{}
|
||||
}
|
||||
|
||||
// example_nameFunc takes an example function name and returns its display
|
||||
// name. For example, "Foo_Bar_quux" becomes "Foo.Bar (Quux)".
|
||||
func (p *Presentation) example_nameFunc(s string) string {
|
||||
@@ -890,8 +858,12 @@ func replaceLeadingIndentation(body, oldIndent, newIndent string) string {
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Write an AST node to w.
|
||||
func (p *Presentation) writeNode(w io.Writer, fset *token.FileSet, x interface{}) {
|
||||
// writeNode writes the AST node x to w.
|
||||
//
|
||||
// The provided fset must be non-nil. The pageInfo is optional. If
|
||||
// present, the pageInfo is used to add comments to struct fields to
|
||||
// say which version of Go introduced them.
|
||||
func (p *Presentation) writeNode(w io.Writer, pageInfo *PageInfo, fset *token.FileSet, x interface{}) {
|
||||
// convert trailing tabs into spaces using a tconv filter
|
||||
// to ensure a good outcome in most browsers (there may still
|
||||
// be tabs in comments and strings, but converting those into
|
||||
@@ -900,15 +872,88 @@ func (p *Presentation) writeNode(w io.Writer, fset *token.FileSet, x interface{}
|
||||
// TODO(gri) rethink printer flags - perhaps tconv can be eliminated
|
||||
// with an another printer mode (which is more efficiently
|
||||
// implemented in the printer than here with another layer)
|
||||
|
||||
var pkgName, structName string
|
||||
var apiInfo pkgAPIVersions
|
||||
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 {
|
||||
if _, ok := ts.Type.(*ast.StructType); ok {
|
||||
structName = ts.Name.Name
|
||||
}
|
||||
}
|
||||
apiInfo = p.Corpus.pkgAPIInfo[pkgName]
|
||||
}
|
||||
|
||||
var out = w
|
||||
var buf bytes.Buffer
|
||||
if structName != "" {
|
||||
out = &buf
|
||||
}
|
||||
|
||||
mode := printer.TabIndent | printer.UseSpaces
|
||||
err := (&printer.Config{Mode: mode, Tabwidth: p.TabWidth}).Fprint(&tconv{p: p, output: w}, fset, x)
|
||||
err := (&printer.Config{Mode: mode, Tabwidth: p.TabWidth}).Fprint(&tconv{p: p, output: out}, fset, x)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
// Add comments to struct fields saying which Go version introducd them.
|
||||
if structName != "" {
|
||||
fieldSince := apiInfo.fieldSince[structName]
|
||||
typeSince := apiInfo.typeSince[structName]
|
||||
// Add/rewrite comments on struct fields to note which Go version added them.
|
||||
var buf2 bytes.Buffer
|
||||
buf2.Grow(buf.Len() + len(" // Added in Go 1.n")*10)
|
||||
bs := bufio.NewScanner(&buf)
|
||||
for bs.Scan() {
|
||||
line := bs.Bytes()
|
||||
field := firstIdent(line)
|
||||
var since string
|
||||
if field != "" {
|
||||
since = fieldSince[field]
|
||||
if since != "" && since == typeSince {
|
||||
// Don't highlight field versions if they were the
|
||||
// same as the struct itself.
|
||||
since = ""
|
||||
}
|
||||
}
|
||||
if since == "" {
|
||||
buf2.Write(line)
|
||||
} else {
|
||||
if bytes.Contains(line, slashSlash) {
|
||||
line = bytes.TrimRight(line, " \t.")
|
||||
buf2.Write(line)
|
||||
buf2.WriteString("; added in Go ")
|
||||
} else {
|
||||
buf2.Write(line)
|
||||
buf2.WriteString(" // Go ")
|
||||
}
|
||||
buf2.WriteString(since)
|
||||
}
|
||||
buf2.WriteByte('\n')
|
||||
}
|
||||
w.Write(buf2.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
var slashSlash = []byte("//")
|
||||
|
||||
// WriteNode writes x to w.
|
||||
// TODO(bgarcia) Is this method needed? It's just a wrapper for p.writeNode.
|
||||
func (p *Presentation) WriteNode(w io.Writer, fset *token.FileSet, x interface{}) {
|
||||
p.writeNode(w, fset, x)
|
||||
p.writeNode(w, nil, fset, x)
|
||||
}
|
||||
|
||||
// firstIdent returns the first identifier in x.
|
||||
// This actually parses "identifiers" that begin with numbers too, but we
|
||||
// never feed it such input, so it's fine.
|
||||
func firstIdent(x []byte) string {
|
||||
x = bytes.TrimSpace(x)
|
||||
i := bytes.IndexFunc(x, func(r rune) bool { return !unicode.IsLetter(r) && !unicode.IsNumber(r) })
|
||||
if i == -1 {
|
||||
return string(x)
|
||||
}
|
||||
return string(x[:i])
|
||||
}
|
||||
|
47
vendor/golang.org/x/tools/godoc/godoc_test.go
generated
vendored
47
vendor/golang.org/x/tools/godoc/godoc_test.go
generated
vendored
@@ -321,3 +321,50 @@ func TestSrcToPkgLinkFunc(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterOutBuildAnnotations(t *testing.T) {
|
||||
// TODO: simplify this by using a multiline string once we stop
|
||||
// using go vet from 1.10 on the build dashboard.
|
||||
// https://golang.org/issue/26627
|
||||
src := []byte("// +build !foo\n" +
|
||||
"// +build !anothertag\n" +
|
||||
"\n" +
|
||||
"// non-tag comment\n" +
|
||||
"\n" +
|
||||
"package foo\n" +
|
||||
"\n" +
|
||||
"func bar() int {\n" +
|
||||
" return 42\n" +
|
||||
"}\n")
|
||||
|
||||
fset := token.NewFileSet()
|
||||
af, err := parser.ParseFile(fset, "foo.go", src, parser.ParseComments)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var found bool
|
||||
for _, cg := range af.Comments {
|
||||
if strings.HasPrefix(cg.Text(), "+build ") {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("TestFilterOutBuildAnnotations is broken: missing build tag in test input")
|
||||
}
|
||||
|
||||
found = false
|
||||
for _, cg := range filterOutBuildAnnotations(af.Comments) {
|
||||
if strings.HasPrefix(cg.Text(), "+build ") {
|
||||
t.Errorf("filterOutBuildAnnotations failed to filter build tag")
|
||||
}
|
||||
|
||||
if strings.Contains(cg.Text(), "non-tag comment") {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("filterOutBuildAnnotations should not remove non-build tag comment")
|
||||
}
|
||||
}
|
||||
|
2
vendor/golang.org/x/tools/godoc/index.go
generated
vendored
2
vendor/golang.org/x/tools/godoc/index.go
generated
vendored
@@ -82,7 +82,7 @@ type interfaceSlice struct {
|
||||
|
||||
// A RunList is a list of entries that can be sorted according to some
|
||||
// criteria. A RunList may be compressed by grouping "runs" of entries
|
||||
// which are equal (according to the sort critera) into a new RunList of
|
||||
// which are equal (according to the sort criteria) into a new RunList of
|
||||
// runs. For instance, a RunList containing pairs (x, y) may be compressed
|
||||
// into a RunList containing pair runs (x, {y}) where each run consists of
|
||||
// a list of y's with the same x.
|
||||
|
26
vendor/golang.org/x/tools/godoc/page.go
generated
vendored
26
vendor/golang.org/x/tools/godoc/page.go
generated
vendored
@@ -10,6 +10,8 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/godoc/env"
|
||||
)
|
||||
|
||||
// Page describes the contents of the top-level godoc webpage.
|
||||
@@ -21,11 +23,13 @@ type Page struct {
|
||||
Query string
|
||||
Body []byte
|
||||
GoogleCN bool // page is being served from golang.google.cn
|
||||
TreeView bool // page needs to contain treeview related js and css
|
||||
|
||||
// filled in by servePage
|
||||
SearchBox bool
|
||||
Playground bool
|
||||
Version string
|
||||
// filled in by ServePage
|
||||
SearchBox bool
|
||||
Playground bool
|
||||
Version string
|
||||
GoogleAnalytics string
|
||||
}
|
||||
|
||||
func (p *Presentation) ServePage(w http.ResponseWriter, page Page) {
|
||||
@@ -35,6 +39,7 @@ func (p *Presentation) ServePage(w http.ResponseWriter, page Page) {
|
||||
page.SearchBox = p.Corpus.IndexEnabled
|
||||
page.Playground = p.ShowPlayground
|
||||
page.Version = runtime.Version()
|
||||
page.GoogleAnalytics = p.GoogleAnalytics
|
||||
applyTemplateToResponseWriter(w, p.GodocHTML, page)
|
||||
}
|
||||
|
||||
@@ -49,20 +54,19 @@ func (p *Presentation) ServeError(w http.ResponseWriter, r *http.Request, relpat
|
||||
}
|
||||
}
|
||||
p.ServePage(w, Page{
|
||||
Title: "File " + relpath,
|
||||
Subtitle: relpath,
|
||||
Body: applyTemplate(p.ErrorHTML, "errorHTML", err),
|
||||
GoogleCN: googleCN(r),
|
||||
Title: "File " + relpath,
|
||||
Subtitle: relpath,
|
||||
Body: applyTemplate(p.ErrorHTML, "errorHTML", err),
|
||||
GoogleCN: googleCN(r),
|
||||
GoogleAnalytics: p.GoogleAnalytics,
|
||||
})
|
||||
}
|
||||
|
||||
var onAppengine = false // overridden in appengine.go when on app engine
|
||||
|
||||
func googleCN(r *http.Request) bool {
|
||||
if r.FormValue("googlecn") != "" {
|
||||
return true
|
||||
}
|
||||
if !onAppengine {
|
||||
if !env.IsProd() {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(r.Host, ".cn") {
|
||||
|
12
vendor/golang.org/x/tools/godoc/pres.go
generated
vendored
12
vendor/golang.org/x/tools/godoc/pres.go
generated
vendored
@@ -34,12 +34,10 @@ type Presentation struct {
|
||||
MethodSetHTML,
|
||||
PackageHTML,
|
||||
PackageRootHTML,
|
||||
PackageText,
|
||||
SearchHTML,
|
||||
SearchDocHTML,
|
||||
SearchCodeHTML,
|
||||
SearchTxtHTML,
|
||||
SearchText,
|
||||
SearchDescXML *template.Template
|
||||
|
||||
// TabWidth optionally specifies the tab width.
|
||||
@@ -47,7 +45,6 @@ type Presentation struct {
|
||||
|
||||
ShowTimestamps bool
|
||||
ShowPlayground bool
|
||||
ShowExamples bool
|
||||
DeclLinks bool
|
||||
|
||||
// SrcMode outputs source code instead of documentation in command-line mode.
|
||||
@@ -92,6 +89,10 @@ type Presentation struct {
|
||||
// body for displaying search results.
|
||||
SearchResults []SearchResultFunc
|
||||
|
||||
// GoogleAnalytics optionally adds Google Analytics via the provided
|
||||
// tracking ID to each page.
|
||||
GoogleAnalytics string
|
||||
|
||||
initFuncMapOnce sync.Once
|
||||
funcMap template.FuncMap
|
||||
templateFuncs template.FuncMap
|
||||
@@ -109,9 +110,8 @@ func NewPresentation(c *Corpus) *Presentation {
|
||||
mux: http.NewServeMux(),
|
||||
fileServer: http.FileServer(httpfs.New(c.fs)),
|
||||
|
||||
TabWidth: 4,
|
||||
ShowExamples: true,
|
||||
DeclLinks: true,
|
||||
TabWidth: 4,
|
||||
DeclLinks: true,
|
||||
SearchResults: []SearchResultFunc{
|
||||
(*Presentation).SearchResultDoc,
|
||||
(*Presentation).SearchResultCode,
|
||||
|
59
vendor/golang.org/x/tools/godoc/proxy/proxy.go
generated
vendored
59
vendor/golang.org/x/tools/godoc/proxy/proxy.go
generated
vendored
@@ -2,30 +2,35 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
// Package proxy proxies requests to the playground's compile and share handlers.
|
||||
// It is designed to run only on the instance of godoc that serves golang.org.
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/log"
|
||||
"google.golang.org/appengine/urlfetch"
|
||||
"golang.org/x/tools/godoc/env"
|
||||
)
|
||||
|
||||
const playgroundURL = "https://play.golang.org"
|
||||
|
||||
var proxy *httputil.ReverseProxy
|
||||
|
||||
func init() {
|
||||
target, _ := url.Parse(playgroundURL)
|
||||
proxy = httputil.NewSingleHostReverseProxy(target)
|
||||
}
|
||||
|
||||
type Request struct {
|
||||
Body string
|
||||
}
|
||||
@@ -41,8 +46,6 @@ type Event struct {
|
||||
Delay time.Duration // time to wait before printing Message
|
||||
}
|
||||
|
||||
const playgroundURL = "https://play.golang.org"
|
||||
|
||||
const expires = 7 * 24 * time.Hour // 1 week
|
||||
var cacheControlHeader = fmt.Sprintf("public, max-age=%d", int(expires.Seconds()))
|
||||
|
||||
@@ -57,21 +60,17 @@ func compile(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx := appengine.NewContext(r)
|
||||
ctx := r.Context()
|
||||
|
||||
body := r.FormValue("body")
|
||||
res := &Response{}
|
||||
req := &Request{Body: body}
|
||||
if err := makeCompileRequest(ctx, req, res); err != nil {
|
||||
log.Errorf(ctx, "compile error: %v", err)
|
||||
log.Printf("ERROR compile error: %v", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
expiresTime := time.Now().Add(expires).UTC()
|
||||
w.Header().Set("Expires", expiresTime.Format(time.RFC1123))
|
||||
w.Header().Set("Cache-Control", cacheControlHeader)
|
||||
|
||||
var out interface{}
|
||||
switch r.FormValue("version") {
|
||||
case "2":
|
||||
@@ -82,9 +81,17 @@ func compile(w http.ResponseWriter, r *http.Request) {
|
||||
Output string `json:"output"`
|
||||
}{res.Errors, flatten(res.Events)}
|
||||
}
|
||||
if err := json.NewEncoder(w).Encode(out); err != nil {
|
||||
log.Errorf(ctx, "encoding response: %v", err)
|
||||
b, err := json.Marshal(out)
|
||||
if err != nil {
|
||||
log.Printf("ERROR encoding response: %v", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
expiresTime := time.Now().Add(expires).UTC()
|
||||
w.Header().Set("Expires", expiresTime.Format(time.RFC1123))
|
||||
w.Header().Set("Cache-Control", cacheControlHeader)
|
||||
w.Write(b)
|
||||
}
|
||||
|
||||
// makePlaygroundRequest sends the given Request to the playground compile
|
||||
@@ -94,17 +101,22 @@ func makeCompileRequest(ctx context.Context, req *Request, res *Response) error
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshalling request: %v", err)
|
||||
}
|
||||
r, err := urlfetch.Client(ctx).Post(playgroundURL+"/compile", "application/json", bytes.NewReader(reqJ))
|
||||
hReq, _ := http.NewRequest("POST", playgroundURL+"/compile", bytes.NewReader(reqJ))
|
||||
hReq.Header.Set("Content-Type", "application/json")
|
||||
hReq = hReq.WithContext(ctx)
|
||||
|
||||
r, err := http.DefaultClient.Do(hReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("making request: %v", err)
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
if r.StatusCode != http.StatusOK {
|
||||
b, _ := ioutil.ReadAll(r.Body)
|
||||
return fmt.Errorf("bad status: %v body:\n%s", r.Status, b)
|
||||
}
|
||||
err = json.NewDecoder(r.Body).Decode(res)
|
||||
if err != nil {
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(res); err != nil {
|
||||
return fmt.Errorf("unmarshalling response: %v", err)
|
||||
}
|
||||
return nil
|
||||
@@ -124,17 +136,14 @@ func share(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
target, _ := url.Parse(playgroundURL)
|
||||
p := httputil.NewSingleHostReverseProxy(target)
|
||||
p.Transport = &urlfetch.Transport{Context: appengine.NewContext(r)}
|
||||
p.ServeHTTP(w, r)
|
||||
proxy.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func googleCN(r *http.Request) bool {
|
||||
if r.FormValue("googlecn") != "" {
|
||||
return true
|
||||
}
|
||||
if appengine.IsDevAppServer() {
|
||||
if !env.IsProd() {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(r.Host, ".cn") {
|
||||
|
14
vendor/golang.org/x/tools/godoc/redirect/redirect.go
generated
vendored
14
vendor/golang.org/x/tools/godoc/redirect/redirect.go
generated
vendored
@@ -99,7 +99,7 @@ var redirects = map[string]string{
|
||||
"/issues": "https://github.com/golang/go/issues",
|
||||
"/issues/new": "https://github.com/golang/go/issues/new",
|
||||
"/play": "http://play.golang.org",
|
||||
"/design": "https://github.com/golang/proposal/tree/master/design",
|
||||
"/design": "https://go.googlesource.com/proposal/+/master/design",
|
||||
|
||||
// In Go 1.2 the references page is part of /doc/.
|
||||
"/ref": "/doc/#references",
|
||||
@@ -191,9 +191,13 @@ func clHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
target := ""
|
||||
// the first CL in rietveld is about 152046, so only treat the id as
|
||||
// a rietveld CL if it is larger than 150000.
|
||||
if n, err := strconv.Atoi(id); err == nil && n > 150000 {
|
||||
|
||||
if n, err := strconv.Atoi(id); err == nil && isRietveldCL(n) {
|
||||
// TODO: Issue 28836: if this Rietveld CL happens to
|
||||
// also be a Gerrit CL, render a disambiguation HTML
|
||||
// page with two links instead. We'll need to make an
|
||||
// RPC (to maintner?) to figure that out. For now just
|
||||
// redirect to rietveld.
|
||||
target = "https://codereview.appspot.com/" + id
|
||||
} else {
|
||||
target = "https://go-review.googlesource.com/" + id
|
||||
@@ -245,6 +249,6 @@ func designHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
name := r.URL.Path[len(prefix):]
|
||||
target := "https://github.com/golang/proposal/blob/master/design/" + name + ".md"
|
||||
target := "https://go.googlesource.com/proposal/+/master/design/" + name + ".md"
|
||||
http.Redirect(w, r, target, http.StatusFound)
|
||||
}
|
||||
|
15
vendor/golang.org/x/tools/godoc/redirect/redirect_test.go
generated
vendored
15
vendor/golang.org/x/tools/godoc/redirect/redirect_test.go
generated
vendored
@@ -53,15 +53,24 @@ func TestRedirects(t *testing.T) {
|
||||
"/wiki/foo": {302, "https://github.com/golang/go/wiki/foo"},
|
||||
"/wiki/foo/": {302, "https://github.com/golang/go/wiki/foo/"},
|
||||
|
||||
"/design": {301, "https://github.com/golang/proposal/tree/master/design"},
|
||||
"/design": {301, "https://go.googlesource.com/proposal/+/master/design"},
|
||||
"/design/": {302, "/design"},
|
||||
"/design/123-foo": {302, "https://github.com/golang/proposal/blob/master/design/123-foo.md"},
|
||||
"/design/text/123-foo": {302, "https://github.com/golang/proposal/blob/master/design/text/123-foo.md"},
|
||||
"/design/123-foo": {302, "https://go.googlesource.com/proposal/+/master/design/123-foo.md"},
|
||||
"/design/text/123-foo": {302, "https://go.googlesource.com/proposal/+/master/design/text/123-foo.md"},
|
||||
|
||||
"/cl/1": {302, "https://go-review.googlesource.com/1"},
|
||||
"/cl/1/": {302, "https://go-review.googlesource.com/1"},
|
||||
"/cl/267120043": {302, "https://codereview.appspot.com/267120043"},
|
||||
"/cl/267120043/": {302, "https://codereview.appspot.com/267120043"},
|
||||
|
||||
// Verify that we're using the Rietveld CL table:
|
||||
"/cl/152046": {302, "https://codereview.appspot.com/152046"},
|
||||
"/cl/152047": {302, "https://go-review.googlesource.com/152047"},
|
||||
"/cl/152048": {302, "https://codereview.appspot.com/152048"},
|
||||
|
||||
// And verify we're using the the "bigEnoughAssumeRietveld" value:
|
||||
"/cl/299999": {302, "https://go-review.googlesource.com/299999"},
|
||||
"/cl/300000": {302, "https://codereview.appspot.com/300000"},
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
1093
vendor/golang.org/x/tools/godoc/redirect/rietveld.go
generated
vendored
Normal file
1093
vendor/golang.org/x/tools/godoc/redirect/rietveld.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
57
vendor/golang.org/x/tools/godoc/search.go
generated
vendored
57
vendor/golang.org/x/tools/godoc/search.go
generated
vendored
@@ -99,11 +99,7 @@ func (p *Presentation) HandleSearch(w http.ResponseWriter, r *http.Request) {
|
||||
query := strings.TrimSpace(r.FormValue("q"))
|
||||
result := p.Corpus.Lookup(query)
|
||||
|
||||
if p.GetPageInfoMode(r)&NoHTML != 0 {
|
||||
p.ServeText(w, applyTemplate(p.SearchText, "searchText", result))
|
||||
return
|
||||
}
|
||||
contents := bytes.Buffer{}
|
||||
var contents bytes.Buffer
|
||||
for _, f := range p.SearchResults {
|
||||
contents.Write(f(p, result))
|
||||
}
|
||||
@@ -137,3 +133,54 @@ func (p *Presentation) serveSearchDesc(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
applyTemplateToResponseWriter(w, p.SearchDescXML, &data)
|
||||
}
|
||||
|
||||
// tocColCount returns the no. of columns
|
||||
// to split the toc table to.
|
||||
func tocColCount(result SearchResult) int {
|
||||
tocLen := tocLen(result)
|
||||
colCount := 0
|
||||
// Simple heuristic based on visual aesthetic in manual testing.
|
||||
switch {
|
||||
case tocLen <= 10:
|
||||
colCount = 1
|
||||
case tocLen <= 20:
|
||||
colCount = 2
|
||||
case tocLen <= 80:
|
||||
colCount = 3
|
||||
default:
|
||||
colCount = 4
|
||||
}
|
||||
return colCount
|
||||
}
|
||||
|
||||
// tocLen calculates the no. of items in the toc table
|
||||
// by going through various fields in the SearchResult
|
||||
// that is rendered in the UI.
|
||||
func tocLen(result SearchResult) int {
|
||||
tocLen := 0
|
||||
for _, val := range result.Idents {
|
||||
if len(val) != 0 {
|
||||
tocLen++
|
||||
}
|
||||
}
|
||||
// If no identifiers, then just one item for the header text "Package <result.Query>".
|
||||
// See searchcode.html for further details.
|
||||
if len(result.Idents) == 0 {
|
||||
tocLen++
|
||||
}
|
||||
if result.Hit != nil {
|
||||
if len(result.Hit.Decls) > 0 {
|
||||
tocLen += len(result.Hit.Decls)
|
||||
// We need one extra item for the header text "Package-level declarations".
|
||||
tocLen++
|
||||
}
|
||||
if len(result.Hit.Others) > 0 {
|
||||
tocLen += len(result.Hit.Others)
|
||||
// We need one extra item for the header text "Local declarations and uses".
|
||||
tocLen++
|
||||
}
|
||||
}
|
||||
// For "textual occurrences".
|
||||
tocLen++
|
||||
return tocLen
|
||||
}
|
||||
|
18
vendor/golang.org/x/tools/godoc/server.go
generated
vendored
18
vendor/golang.org/x/tools/godoc/server.go
generated
vendored
@@ -208,6 +208,7 @@ func (h *handlerServer) GetPageInfo(abspath, relpath string, mode PageInfoMode,
|
||||
timestamp = ts
|
||||
}
|
||||
if dir == nil {
|
||||
// TODO(agnivade): handle this case better, now since there is no CLI mode.
|
||||
// no directory tree present (happens in command-line mode);
|
||||
// compute 2 levels for this page. The second level is to
|
||||
// get the synopses of sub-directories.
|
||||
@@ -276,11 +277,6 @@ func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if mode&NoHTML != 0 {
|
||||
h.p.ServeText(w, applyTemplate(h.p.PackageText, "packageText", info))
|
||||
return
|
||||
}
|
||||
|
||||
var tabtitle, title, subtitle string
|
||||
switch {
|
||||
case info.PAst != nil:
|
||||
@@ -320,6 +316,7 @@ func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Emit JSON array for type information.
|
||||
pi := h.c.Analysis.PackageInfo(relpath)
|
||||
hasTreeView := len(pi.CallGraph) != 0
|
||||
info.CallGraphIndex = pi.CallGraphIndex
|
||||
info.CallGraph = htmltemplate.JS(marshalJSON(pi.CallGraph))
|
||||
info.AnalysisData = htmltemplate.JS(marshalJSON(pi.Types))
|
||||
@@ -341,6 +338,7 @@ func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
Subtitle: subtitle,
|
||||
Body: body,
|
||||
GoogleCN: info.GoogleCN,
|
||||
TreeView: hasTreeView,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -658,7 +656,15 @@ func formatGoSource(buf *bytes.Buffer, text []byte, links []analysis.Link, patte
|
||||
//
|
||||
// The first tab for the code snippet needs to start in column 9, so
|
||||
// it indents a full 8 spaces, hence the two nbsp's. Otherwise the tab
|
||||
// character only indents about two spaces.
|
||||
// character only indents a short amount.
|
||||
//
|
||||
// Due to rounding and font width Firefox might not treat 8 rendered
|
||||
// characters as 8 characters wide, and subsequently may treat the tab
|
||||
// character in the 9th position as moving the width from (7.5 or so) up
|
||||
// to 8. See
|
||||
// https://github.com/webcompat/web-bugs/issues/17530#issuecomment-402675091
|
||||
// for a fuller explanation. The solution is to add a CSS class to
|
||||
// explicitly declare the width to be 8 characters.
|
||||
fmt.Fprintf(saved, `<span id="L%d" class="ln">%6d </span>`, n, n)
|
||||
n++
|
||||
saved.Write(line)
|
||||
|
81
vendor/golang.org/x/tools/godoc/short/short.go
generated
vendored
81
vendor/golang.org/x/tools/godoc/short/short.go
generated
vendored
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
// +build golangorg
|
||||
|
||||
// Package short implements a simple URL shortener, serving an administrative
|
||||
// interface at /s and shortened urls from /s/key.
|
||||
@@ -12,19 +12,18 @@ package short
|
||||
// TODO(adg): collect statistics on URL visits
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/datastore"
|
||||
"google.golang.org/appengine/log"
|
||||
"google.golang.org/appengine/memcache"
|
||||
"cloud.google.com/go/datastore"
|
||||
"golang.org/x/tools/internal/memcache"
|
||||
"google.golang.org/appengine/user"
|
||||
)
|
||||
|
||||
@@ -41,17 +40,32 @@ type Link struct {
|
||||
|
||||
var validKey = regexp.MustCompile(`^[a-zA-Z0-9-_.]+$`)
|
||||
|
||||
func RegisterHandlers(mux *http.ServeMux) {
|
||||
mux.HandleFunc(prefix, adminHandler)
|
||||
mux.HandleFunc(prefix+"/", linkHandler)
|
||||
type server struct {
|
||||
datastore *datastore.Client
|
||||
memcache *memcache.CodecClient
|
||||
}
|
||||
|
||||
func RegisterHandlers(mux *http.ServeMux, dc *datastore.Client, mc *memcache.Client) {
|
||||
s := server{dc, mc.WithCodec(memcache.JSON)}
|
||||
mux.HandleFunc(prefix+"/", s.linkHandler)
|
||||
|
||||
// TODO(cbro): move storage of the links to a text file in Gerrit.
|
||||
// Disable the admin handler until that happens, since GAE Flex doesn't support
|
||||
// the "google.golang.org/appengine/user" package.
|
||||
// See golang.org/issue/27205#issuecomment-418673218
|
||||
// mux.HandleFunc(prefix, adminHandler)
|
||||
mux.HandleFunc(prefix, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
io.WriteString(w, "Link creation temporarily unavailable. See golang.org/issue/27205.")
|
||||
})
|
||||
}
|
||||
|
||||
// linkHandler services requests to short URLs.
|
||||
// http://golang.org/s/key
|
||||
// It consults memcache and datastore for the Link for key.
|
||||
// It then sends a redirects or an error message.
|
||||
func linkHandler(w http.ResponseWriter, r *http.Request) {
|
||||
c := appengine.NewContext(r)
|
||||
func (h server) linkHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
key := r.URL.Path[len(prefix)+1:]
|
||||
if !validKey.MatchString(key) {
|
||||
@@ -60,16 +74,15 @@ func linkHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
var link Link
|
||||
_, err := memcache.JSON.Get(c, cacheKey(key), &link)
|
||||
if err != nil {
|
||||
k := datastore.NewKey(c, kind, key, 0, nil)
|
||||
err = datastore.Get(c, k, &link)
|
||||
if err := h.memcache.Get(ctx, cacheKey(key), &link); err != nil {
|
||||
k := datastore.NameKey(kind, key, nil)
|
||||
err = h.datastore.Get(ctx, k, &link)
|
||||
switch err {
|
||||
case datastore.ErrNoSuchEntity:
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
return
|
||||
default: // != nil
|
||||
log.Errorf(c, "%q: %v", key, err)
|
||||
log.Printf("ERROR %q: %v", key, err)
|
||||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
case nil:
|
||||
@@ -77,8 +90,8 @@ func linkHandler(w http.ResponseWriter, r *http.Request) {
|
||||
Key: cacheKey(key),
|
||||
Object: &link,
|
||||
}
|
||||
if err := memcache.JSON.Set(c, item); err != nil {
|
||||
log.Warningf(c, "%q: %v", key, err)
|
||||
if err := h.memcache.Set(ctx, item); err != nil {
|
||||
log.Printf("WARNING %q: %v", key, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,10 +102,10 @@ func linkHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var adminTemplate = template.Must(template.New("admin").Parse(templateHTML))
|
||||
|
||||
// adminHandler serves an administrative interface.
|
||||
func adminHandler(w http.ResponseWriter, r *http.Request) {
|
||||
c := appengine.NewContext(r)
|
||||
func (h server) adminHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
if !user.IsAdmin(c) {
|
||||
if !user.IsAdmin(ctx) {
|
||||
http.Error(w, "forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
@@ -104,24 +117,24 @@ func adminHandler(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.FormValue("do") {
|
||||
case "Add":
|
||||
newLink = &Link{key, r.FormValue("target")}
|
||||
doErr = putLink(c, newLink)
|
||||
doErr = h.putLink(ctx, newLink)
|
||||
case "Delete":
|
||||
k := datastore.NewKey(c, kind, key, 0, nil)
|
||||
doErr = datastore.Delete(c, k)
|
||||
k := datastore.NameKey(kind, key, nil)
|
||||
doErr = h.datastore.Delete(ctx, k)
|
||||
default:
|
||||
http.Error(w, "unknown action", http.StatusBadRequest)
|
||||
}
|
||||
err := memcache.Delete(c, cacheKey(key))
|
||||
err := h.memcache.Delete(ctx, cacheKey(key))
|
||||
if err != nil && err != memcache.ErrCacheMiss {
|
||||
log.Warningf(c, "%q: %v", key, err)
|
||||
log.Printf("WARNING %q: %v", key, err)
|
||||
}
|
||||
}
|
||||
|
||||
var links []*Link
|
||||
_, err := datastore.NewQuery(kind).Order("Key").GetAll(c, &links)
|
||||
if err != nil {
|
||||
q := datastore.NewQuery(kind).Order("Key")
|
||||
if _, err := h.datastore.GetAll(ctx, q, &links); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
log.Errorf(c, "%v", err)
|
||||
log.Printf("ERROR %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -150,20 +163,20 @@ func adminHandler(w http.ResponseWriter, r *http.Request) {
|
||||
Error error
|
||||
}{baseURL, prefix, links, newLink, doErr}
|
||||
if err := adminTemplate.Execute(w, &data); err != nil {
|
||||
log.Criticalf(c, "adminTemplate: %v", err)
|
||||
log.Printf("ERROR adminTemplate: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// putLink validates the provided link and puts it into the datastore.
|
||||
func putLink(c context.Context, link *Link) error {
|
||||
func (h server) putLink(ctx context.Context, link *Link) error {
|
||||
if !validKey.MatchString(link.Key) {
|
||||
return errors.New("invalid key; must match " + validKey.String())
|
||||
}
|
||||
if _, err := url.Parse(link.Target); err != nil {
|
||||
return fmt.Errorf("bad target: %v", err)
|
||||
}
|
||||
k := datastore.NewKey(c, kind, link.Key, 0, nil)
|
||||
_, err := datastore.Put(c, k, link)
|
||||
k := datastore.NameKey(kind, link.Key, nil)
|
||||
_, err := h.datastore.Put(ctx, k, link)
|
||||
return err
|
||||
}
|
||||
|
||||
|
2
vendor/golang.org/x/tools/godoc/short/tmpl.go
generated
vendored
2
vendor/golang.org/x/tools/godoc/short/tmpl.go
generated
vendored
@@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package short
|
||||
|
||||
const templateHTML = `
|
||||
|
2
vendor/golang.org/x/tools/godoc/snippet.go
generated
vendored
2
vendor/golang.org/x/tools/godoc/snippet.go
generated
vendored
@@ -24,7 +24,7 @@ type Snippet struct {
|
||||
func (p *Presentation) newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
|
||||
// TODO instead of pretty-printing the node, should use the original source instead
|
||||
var buf1 bytes.Buffer
|
||||
p.writeNode(&buf1, fset, decl)
|
||||
p.writeNode(&buf1, nil, fset, decl)
|
||||
// wrap text with <pre> tag
|
||||
var buf2 bytes.Buffer
|
||||
buf2.WriteString("<pre>")
|
||||
|
2
vendor/golang.org/x/tools/godoc/static/gen.go
generated
vendored
2
vendor/golang.org/x/tools/godoc/static/gen.go
generated
vendored
@@ -57,11 +57,9 @@ var files = []string{
|
||||
"opensearch.xml",
|
||||
"package.html",
|
||||
"packageroot.html",
|
||||
"package.txt",
|
||||
"play.js",
|
||||
"playground.js",
|
||||
"search.html",
|
||||
"search.txt",
|
||||
"searchcode.html",
|
||||
"searchdoc.html",
|
||||
"searchtxt.html",
|
||||
|
28
vendor/golang.org/x/tools/godoc/static/godoc.html
generated
vendored
28
vendor/golang.org/x/tools/godoc/static/godoc.html
generated
vendored
@@ -13,11 +13,28 @@
|
||||
{{if .SearchBox}}
|
||||
<link rel="search" type="application/opensearchdescription+xml" title="godoc" href="/opensearch.xml" />
|
||||
{{end}}
|
||||
{{if .TreeView}}
|
||||
<link rel="stylesheet" href="/lib/godoc/jquery.treeview.css">
|
||||
{{end}}
|
||||
<script>window.initFuncs = [];</script>
|
||||
{{with .GoogleAnalytics}}
|
||||
<script type="text/javascript">
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(["_setAccount", "{{.}}"]);
|
||||
window.trackPageview = function() {
|
||||
_gaq.push(["_trackPageview", location.pathname+location.hash]);
|
||||
};
|
||||
window.trackPageview();
|
||||
window.trackEvent = function(category, action, opt_label, opt_value, opt_noninteraction) {
|
||||
_gaq.push(["_trackEvent", category, action, opt_label, opt_value, opt_noninteraction]);
|
||||
};
|
||||
</script>
|
||||
{{end}}
|
||||
<script src="/lib/godoc/jquery.js" defer></script>
|
||||
{{if .TreeView}}
|
||||
<script src="/lib/godoc/jquery.treeview.js" defer></script>
|
||||
<script src="/lib/godoc/jquery.treeview.edit.js" defer></script>
|
||||
{{end}}
|
||||
|
||||
{{if .Playground}}
|
||||
<script src="/lib/godoc/playground.js" defer></script>
|
||||
@@ -44,7 +61,7 @@
|
||||
{{if not .GoogleCN}}
|
||||
<a href="/blog/">Blog</a>
|
||||
{{end}}
|
||||
{{if .Playground}}
|
||||
{{if (and .Playground .Title)}}
|
||||
<a id="playgroundButton" href="http://play.golang.org/" title="Show Go Playground">Play</a>
|
||||
{{end}}
|
||||
<span class="search-box"><input type="search" id="search" name="q" placeholder="Search" aria-label="Search" required><button type="submit"><span><!-- magnifying glass: --><svg width="24" height="24" viewBox="0 0 24 24"><title>submit search</title><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/><path d="M0 0h24v24H0z" fill="none"/></svg></span></button></span>
|
||||
@@ -112,6 +129,15 @@ and code is licensed under a <a href="/LICENSE">BSD license</a>.<br>
|
||||
|
||||
</div><!-- .container -->
|
||||
</div><!-- #page -->
|
||||
{{if .GoogleAnalytics}}
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;
|
||||
ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
|
||||
var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
{{end}}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
22
vendor/golang.org/x/tools/godoc/static/godocs.js
generated
vendored
22
vendor/golang.org/x/tools/godoc/static/godocs.js
generated
vendored
@@ -34,6 +34,13 @@ function generateTOC() {
|
||||
return;
|
||||
}
|
||||
|
||||
// For search, we send the toc precomputed from server-side.
|
||||
// TODO: Ideally, this should always be precomputed for all pages, but then
|
||||
// we need to do HTML parsing on the server-side.
|
||||
if (location.pathname === '/search') {
|
||||
return;
|
||||
}
|
||||
|
||||
var nav = $('#nav');
|
||||
if (nav.length === 0) {
|
||||
return;
|
||||
@@ -57,7 +64,6 @@ function generateTOC() {
|
||||
if (toc_items.length <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var dl1 = $('<dl/>');
|
||||
var dl2 = $('<dl/>');
|
||||
|
||||
@@ -149,8 +155,16 @@ function setupDropdownPlayground() {
|
||||
button.removeClass('active');
|
||||
div.hide();
|
||||
});
|
||||
button.show();
|
||||
$('#menu').css('min-width', '+=60');
|
||||
|
||||
// Hide inline playground if we click somewhere on the page.
|
||||
// This is needed in mobile devices, where the "Play" button
|
||||
// is not clickable once the playground opens up.
|
||||
$("#page").click(function() {
|
||||
if (button.hasClass('active')) {
|
||||
button.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setupInlinePlayground() {
|
||||
@@ -253,13 +267,13 @@ function personalizeInstallInstructions() {
|
||||
|
||||
var filename = s.substr(prefix.length);
|
||||
var filenameRE = /^go1\.\d+(\.\d+)?([a-z0-9]+)?\.([a-z0-9]+)(-[a-z0-9]+)?(-osx10\.[68])?\.([a-z.]+)$/;
|
||||
$('.downloadFilename').text(filename);
|
||||
$('.hideFromDownload').hide();
|
||||
var m = filenameRE.exec(filename);
|
||||
if (!m) {
|
||||
// Can't interpret file name; bail.
|
||||
return;
|
||||
}
|
||||
$('.downloadFilename').text(filename);
|
||||
$('.hideFromDownload').hide();
|
||||
|
||||
var os = m[3];
|
||||
var ext = m[6];
|
||||
|
12
vendor/golang.org/x/tools/godoc/static/package.html
generated
vendored
12
vendor/golang.org/x/tools/godoc/static/package.html
generated
vendored
@@ -10,7 +10,7 @@
|
||||
correspond to Go identifiers).
|
||||
-->
|
||||
{{with .PDoc}}
|
||||
<script type='text/javascript'>
|
||||
<script>
|
||||
document.ANALYSIS_DATA = {{$.AnalysisData}};
|
||||
document.CALLGRAPH = {{$.CallGraph}};
|
||||
</script>
|
||||
@@ -112,6 +112,7 @@
|
||||
</div><!-- .expanded -->
|
||||
</div><!-- #pkg-index -->
|
||||
|
||||
{{if ne $.CallGraph "null"}}
|
||||
<div id="pkg-callgraph" class="toggle" style="display: none">
|
||||
<div class="collapsed">
|
||||
<h2 class="toggleButton" title="Click to show Internal Call Graph section">Internal call graph ▹</h2>
|
||||
@@ -148,6 +149,7 @@
|
||||
<ul style="margin-left: 0.5in" id="callgraph-0" class="treeview"></ul>
|
||||
</div>
|
||||
</div> <!-- #pkg-callgraph -->
|
||||
{{end}}
|
||||
|
||||
{{with .Consts}}
|
||||
<h2 id="pkg-constants">Constants</h2>
|
||||
@@ -168,6 +170,8 @@
|
||||
{{$name_html := html .Name}}
|
||||
<h2 id="{{$name_html}}">func <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a>
|
||||
<a class="permalink" href="#{{$name_html}}">¶</a>
|
||||
{{$since := since "func" "" .Name $.PDoc.ImportPath}}
|
||||
{{if $since}}<span title="Added in Go {{$since}}">{{$since}}</span>{{end}}
|
||||
</h2>
|
||||
<pre>{{node_html $ .Decl true}}</pre>
|
||||
{{comment_html .Doc}}
|
||||
@@ -180,6 +184,8 @@
|
||||
{{$tname_html := html .Name}}
|
||||
<h2 id="{{$tname_html}}">type <a href="{{posLink_url $ .Decl}}">{{$tname_html}}</a>
|
||||
<a class="permalink" href="#{{$tname_html}}">¶</a>
|
||||
{{$since := since "type" "" .Name $.PDoc.ImportPath}}
|
||||
{{if $since}}<span title="Added in Go {{$since}}">{{$since}}</span>{{end}}
|
||||
</h2>
|
||||
{{comment_html .Doc}}
|
||||
<pre>{{node_html $ .Decl true}}</pre>
|
||||
@@ -202,6 +208,8 @@
|
||||
{{$name_html := html .Name}}
|
||||
<h3 id="{{$name_html}}">func <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a>
|
||||
<a class="permalink" href="#{{$name_html}}">¶</a>
|
||||
{{$since := since "func" "" .Name $.PDoc.ImportPath}}
|
||||
{{if $since}}<span title="Added in Go {{$since}}">{{$since}}</span>{{end}}
|
||||
</h3>
|
||||
<pre>{{node_html $ .Decl true}}</pre>
|
||||
{{comment_html .Doc}}
|
||||
@@ -213,6 +221,8 @@
|
||||
{{$name_html := html .Name}}
|
||||
<h3 id="{{$tname_html}}.{{$name_html}}">func ({{html .Recv}}) <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a>
|
||||
<a class="permalink" href="#{{$tname_html}}.{{$name_html}}">¶</a>
|
||||
{{$since := since "method" .Recv .Name $.PDoc.ImportPath}}
|
||||
{{if $since}}<span title="Added in Go {{$since}}">{{$since}}</span>{{end}}
|
||||
</h3>
|
||||
<pre>{{node_html $ .Decl true}}</pre>
|
||||
{{comment_html .Doc}}
|
||||
|
116
vendor/golang.org/x/tools/godoc/static/package.txt
generated
vendored
116
vendor/golang.org/x/tools/godoc/static/package.txt
generated
vendored
@@ -1,116 +0,0 @@
|
||||
{{$info := .}}{{$filtered := .IsFiltered}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{if $filtered}}{{range .PAst}}{{range .Decls}}{{node $info .}}
|
||||
|
||||
{{end}}{{end}}{{else}}{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}:
|
||||
{{node $ $ast}}{{end}}{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{if and $filtered (not (or .PDoc .PAst))}}No match found.
|
||||
{{end}}{{with .PDoc}}{{if $.IsMain}}COMMAND DOCUMENTATION
|
||||
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{else}}{{if not $filtered}}PACKAGE DOCUMENTATION
|
||||
|
||||
package {{.Name}}
|
||||
import "{{.ImportPath}}"
|
||||
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{example_text $ "" " "}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Consts}}{{if not $filtered}}CONSTANTS
|
||||
|
||||
{{end}}{{range .}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Vars}}{{if not $filtered}}VARIABLES
|
||||
|
||||
{{end}}{{range .}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Funcs}}{{if not $filtered}}FUNCTIONS
|
||||
|
||||
{{end}}{{range .}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{example_text $ .Name " "}}{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Types}}{{if not $filtered}}TYPES
|
||||
|
||||
{{end}}{{range .}}{{$tname := .Name}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{if .Consts}}{{range .Consts}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{if .Vars}}{{range .Vars}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{range $name := .Names}}{{example_text $ $name " "}}{{end}}{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{if .Funcs}}{{range .Funcs}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{example_text $ .Name " "}}{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{if .Methods}}{{range .Methods}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{$name := printf "%s_%s" $tname .Name}}{{example_text $ $name " "}}{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{if and $filtered (not (or .Consts (or .Vars (or .Funcs .Types))))}}No match found.
|
||||
{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with $.Notes}}
|
||||
{{range $marker, $content := .}}
|
||||
{{$marker}}S
|
||||
|
||||
{{range $content}}{{comment_text .Body " " "\t"}}
|
||||
{{end}}{{end}}{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{if not $filtered}}{{with .Dirs}}SUBDIRECTORIES
|
||||
{{if $.DirFlat}}{{range .List}}{{if .HasPkg}}
|
||||
{{.Path}}{{end}}{{end}}
|
||||
{{else}}{{range .List}}
|
||||
{{repeat `. ` .Depth}}{{.Name}}{{end}}
|
||||
{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{end}}{{/*
|
||||
Make sure there is no newline at the end of this file.
|
||||
perl -i -pe 'chomp if eof' package.txt
|
||||
*/}}
|
47
vendor/golang.org/x/tools/godoc/static/playground.js
generated
vendored
47
vendor/golang.org/x/tools/godoc/static/playground.js
generated
vendored
@@ -46,12 +46,36 @@ here's a skeleton implementation of a playground transport.
|
||||
function HTTPTransport(enableVet) {
|
||||
'use strict';
|
||||
|
||||
function playback(output, events) {
|
||||
function playback(output, data) {
|
||||
// Backwards compatibility: default values do not affect the output.
|
||||
var events = data.Events || [];
|
||||
var errors = data.Errors || "";
|
||||
var status = data.Status || 0;
|
||||
var isTest = data.IsTest || false;
|
||||
var testsFailed = data.TestsFailed || 0;
|
||||
|
||||
var timeout;
|
||||
output({Kind: 'start'});
|
||||
function next() {
|
||||
if (!events || events.length === 0) {
|
||||
output({Kind: 'end'});
|
||||
if (isTest) {
|
||||
if (testsFailed > 0) {
|
||||
output({Kind: 'system', Body: '\n'+testsFailed+' test'+(testsFailed>1?'s':'')+' failed.'});
|
||||
} else {
|
||||
output({Kind: 'system', Body: '\nAll tests passed.'});
|
||||
}
|
||||
} else {
|
||||
if (status > 0) {
|
||||
output({Kind: 'end', Body: 'status ' + status + '.'});
|
||||
} else {
|
||||
if (errors !== "") {
|
||||
// errors are displayed only in the case of timeout.
|
||||
output({Kind: 'end', Body: errors + '.'});
|
||||
} else {
|
||||
output({Kind: 'end'});
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
var e = events.shift();
|
||||
@@ -79,6 +103,12 @@ function HTTPTransport(enableVet) {
|
||||
output({Kind: 'end'});
|
||||
}
|
||||
|
||||
function buildFailed(output, msg) {
|
||||
output({Kind: 'start'});
|
||||
output({Kind: 'stderr', Body: msg});
|
||||
output({Kind: 'system', Body: '\nGo build failed.'});
|
||||
}
|
||||
|
||||
var seq = 0;
|
||||
return {
|
||||
Run: function(body, output, options) {
|
||||
@@ -94,12 +124,17 @@ function HTTPTransport(enableVet) {
|
||||
if (!data) return;
|
||||
if (playing != null) playing.Stop();
|
||||
if (data.Errors) {
|
||||
error(output, data.Errors);
|
||||
if (data.Errors === 'process took too long') {
|
||||
// Playback the output that was captured before the timeout.
|
||||
playing = playback(output, data);
|
||||
} else {
|
||||
buildFailed(output, data.Errors);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enableVet) {
|
||||
playing = playback(output, data.Events);
|
||||
playing = playback(output, data);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -116,10 +151,10 @@ function HTTPTransport(enableVet) {
|
||||
data.Events.unshift({Message: 'Go vet exited.\n\n', Kind: 'system', Delay: 0});
|
||||
data.Events.unshift({Message: dataVet.Errors, Kind: 'stderr', Delay: 0});
|
||||
}
|
||||
playing = playback(output, data.Events);
|
||||
playing = playback(output, data);
|
||||
},
|
||||
error: function() {
|
||||
playing = playback(output, data.Events);
|
||||
playing = playback(output, data);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
48
vendor/golang.org/x/tools/godoc/static/search.html
generated
vendored
48
vendor/golang.org/x/tools/godoc/static/search.html
generated
vendored
@@ -3,6 +3,54 @@
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file.
|
||||
-->
|
||||
|
||||
{{ $colCount := tocColCount .}}
|
||||
{{/* Generate the TOC */}}
|
||||
<nav class="search-nav" style="column-count: {{$colCount}}" role="navigation">
|
||||
{{range $key, $val := .Idents}}
|
||||
{{if $val}}
|
||||
<a href="#{{$key.Name}}">{{$key.Name}}</a>
|
||||
<br />
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if not .Idents}}
|
||||
{{with .Pak}}
|
||||
<a href="#Packages">Package {{html $.Query}}</a>
|
||||
<br />
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{with .Hit}}
|
||||
{{with .Decls}}
|
||||
<a href="#Global">Package-level declarations</a>
|
||||
<br />
|
||||
{{range .}}
|
||||
{{$pkg_html := pkgLink .Pak.Path | html}}
|
||||
<a href="#Global_{{$pkg_html}}" class="indent">package {{html .Pak.Name}}</a>
|
||||
<br />
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{with .Others}}
|
||||
<a href="#Local">Local declarations and uses</a>
|
||||
<br />
|
||||
{{range .}}
|
||||
{{$pkg_html := pkgLink .Pak.Path | html}}
|
||||
<a href="#Local_{{$pkg_html}}" class="indent">package {{html .Pak.Name}}</a>
|
||||
<br />
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{with .Textual}}
|
||||
{{if $.Complete}}
|
||||
<a href="#Textual">{{html $.Found}} textual occurrences</a>
|
||||
{{else}}
|
||||
<a href="#Textual">More than {{html $.Found}} textual occurrences</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</nav>
|
||||
|
||||
{{with .Alert}}
|
||||
<p>
|
||||
<span class="alert" style="font-size:120%">{{html .}}</span>
|
||||
|
54
vendor/golang.org/x/tools/godoc/static/search.txt
generated
vendored
54
vendor/golang.org/x/tools/godoc/static/search.txt
generated
vendored
@@ -1,54 +0,0 @@
|
||||
QUERY
|
||||
{{.Query}}
|
||||
|
||||
{{with .Alert}}{{.}}
|
||||
{{end}}{{/* .Alert */}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Alt}}DID YOU MEAN
|
||||
|
||||
{{range .Alts}} {{.}}
|
||||
{{end}}
|
||||
{{end}}{{/* .Alt */}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Pak}}PACKAGE {{$.Query}}
|
||||
|
||||
{{range .}} {{pkgLink .Pak.Path}}
|
||||
{{end}}
|
||||
{{end}}{{/* .Pak */}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{range $key, $val := .Idents}}{{if $val}}{{$key.Name}}
|
||||
{{range $val}} {{.Path}}.{{.Name}}
|
||||
{{end}}
|
||||
{{end}}{{end}}{{/* .Idents */}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Hit}}{{with .Decls}}PACKAGE-LEVEL DECLARATIONS
|
||||
|
||||
{{range .}}package {{.Pak.Name}}
|
||||
{{range $file := .Files}}{{range .Groups}}{{range .}} {{srcLink $file.File.Path}}:{{infoLine .}}{{end}}
|
||||
{{end}}{{end}}{{/* .Files */}}
|
||||
{{end}}{{end}}{{/* .Decls */}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Others}}LOCAL DECLARATIONS AND USES
|
||||
|
||||
{{range .}}package {{.Pak.Name}}
|
||||
{{range $file := .Files}}{{range .Groups}}{{range .}} {{srcLink $file.File.Path}}:{{infoLine .}}
|
||||
{{end}}{{end}}{{end}}{{/* .Files */}}
|
||||
{{end}}{{end}}{{/* .Others */}}{{end}}{{/* .Hit */}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{if .Textual}}{{if .Complete}}{{.Found}} TEXTUAL OCCURRENCES{{else}}MORE THAN {{.Found}} TEXTUAL OCCURRENCES{{end}}
|
||||
|
||||
{{range .Textual}}{{len .Lines}} {{srcLink .Filename}}
|
||||
{{end}}{{if not .Complete}}... ...
|
||||
{{end}}{{end}}
|
16
vendor/golang.org/x/tools/godoc/static/static.go
generated
vendored
16
vendor/golang.org/x/tools/godoc/static/static.go
generated
vendored
File diff suppressed because one or more lines are too long
42
vendor/golang.org/x/tools/godoc/static/style.css
generated
vendored
42
vendor/golang.org/x/tools/godoc/static/style.css
generated
vendored
@@ -37,6 +37,26 @@ pre .ln {
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
/* Ensure 8 characters in the document - which due to floating
|
||||
* point rendering issues, might have a width of less than 1 each - are 8
|
||||
* characters wide, so a tab in the 9th position indents properly. See
|
||||
* https://github.com/webcompat/web-bugs/issues/17530#issuecomment-402675091
|
||||
* for more information. */
|
||||
display: inline-block;
|
||||
width: 8ch;
|
||||
}
|
||||
|
||||
.search-nav{
|
||||
margin-left: 1.25rem;
|
||||
font-size: 0.875rem;
|
||||
column-gap: 1.25rem;
|
||||
column-fill: auto;
|
||||
column-width: 14rem;
|
||||
}
|
||||
|
||||
.search-nav .indent {
|
||||
margin-left: 1.25rem;
|
||||
}
|
||||
|
||||
a,
|
||||
@@ -103,12 +123,17 @@ h2 {
|
||||
padding: 0.5rem;
|
||||
line-height: 1.25;
|
||||
font-weight: normal;
|
||||
overflow: auto;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
h2 a {
|
||||
font-weight: bold;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.25;
|
||||
overflow: auto;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
h3,
|
||||
h4 {
|
||||
@@ -122,6 +147,14 @@ h4 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h2 > span,
|
||||
h3 > span {
|
||||
float: right;
|
||||
margin: 0 25px 0 0;
|
||||
font-weight: normal;
|
||||
color: #5279C7;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin: 1.25rem;
|
||||
}
|
||||
@@ -297,6 +330,9 @@ input#search {
|
||||
max-width: 100%;
|
||||
min-width: 5.625rem;
|
||||
}
|
||||
input#search:-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
input#search:-moz-ui-invalid {
|
||||
box-shadow: unset;
|
||||
}
|
||||
@@ -603,7 +639,6 @@ div.play .buttons a {
|
||||
}
|
||||
|
||||
/* drop-down playground */
|
||||
#playgroundButton,
|
||||
div#playground {
|
||||
/* start hidden; revealed by javascript */
|
||||
display: none;
|
||||
@@ -740,6 +775,11 @@ a.error {
|
||||
font-size: 0.9375rem;
|
||||
}
|
||||
|
||||
div#playground {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
pre,
|
||||
code {
|
||||
font-size: 0.866rem;
|
||||
|
224
vendor/golang.org/x/tools/godoc/versions.go
generated
vendored
Normal file
224
vendor/golang.org/x/tools/godoc/versions.go
generated
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
// 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.
|
||||
|
||||
// This file caches information about which standard library types, methods,
|
||||
// and functions appeared in what version of Go
|
||||
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"go/build"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// apiVersions is a map of packages to information about those packages'
|
||||
// symbols and when they were added to Go.
|
||||
//
|
||||
// Only things added after Go1 are tracked. Version strings are of the
|
||||
// form "1.1", "1.2", etc.
|
||||
type apiVersions map[string]pkgAPIVersions // keyed by Go package ("net/http")
|
||||
|
||||
// pkgAPIVersions contains information about which version of Go added
|
||||
// certain package symbols.
|
||||
//
|
||||
// Only things added after Go1 are tracked. Version strings are of the
|
||||
// form "1.1", "1.2", etc.
|
||||
type pkgAPIVersions struct {
|
||||
typeSince map[string]string // "Server" -> "1.7"
|
||||
methodSince map[string]map[string]string // "*Server" ->"Shutdown"->1.8
|
||||
funcSince map[string]string // "NewServer" -> "1.7"
|
||||
fieldSince map[string]map[string]string // "ClientTrace" -> "Got1xxResponse" -> "1.11"
|
||||
}
|
||||
|
||||
// sinceVersionFunc returns a string (such as "1.7") specifying which Go
|
||||
// version introduced a symbol, unless it was introduced in Go1, in
|
||||
// which case it returns the empty string.
|
||||
//
|
||||
// The kind is one of "type", "method", or "func".
|
||||
//
|
||||
// The receiver is only used for "methods" and specifies the receiver type,
|
||||
// such as "*Server".
|
||||
//
|
||||
// The name is the symbol name ("Server") and the pkg is the package
|
||||
// ("net/http").
|
||||
func (v apiVersions) sinceVersionFunc(kind, receiver, name, pkg string) string {
|
||||
pv := v[pkg]
|
||||
switch kind {
|
||||
case "func":
|
||||
return pv.funcSince[name]
|
||||
case "type":
|
||||
return pv.typeSince[name]
|
||||
case "method":
|
||||
return pv.methodSince[receiver][name]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// versionedRow represents an API feature, a parsed line of a
|
||||
// $GOROOT/api/go.*txt file.
|
||||
type versionedRow struct {
|
||||
pkg string // "net/http"
|
||||
kind string // "type", "func", "method", "field" TODO: "const", "var"
|
||||
recv string // for methods, the receiver type ("Server", "*Server")
|
||||
name string // name of type, (struct) field, func, method
|
||||
structName string // for struct fields, the outer struct name
|
||||
}
|
||||
|
||||
// versionParser parses $GOROOT/api/go*.txt files and stores them in in its rows field.
|
||||
type versionParser struct {
|
||||
res apiVersions // initialized lazily
|
||||
}
|
||||
|
||||
func (vp *versionParser) parseFile(name string) error {
|
||||
base := filepath.Base(name)
|
||||
ver := strings.TrimPrefix(strings.TrimSuffix(base, ".txt"), "go")
|
||||
if ver == "1" {
|
||||
return nil
|
||||
}
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
sc := bufio.NewScanner(f)
|
||||
for sc.Scan() {
|
||||
row, ok := parseRow(sc.Text())
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if vp.res == nil {
|
||||
vp.res = make(apiVersions)
|
||||
}
|
||||
pkgi, ok := vp.res[row.pkg]
|
||||
if !ok {
|
||||
pkgi = pkgAPIVersions{
|
||||
typeSince: make(map[string]string),
|
||||
methodSince: make(map[string]map[string]string),
|
||||
funcSince: make(map[string]string),
|
||||
fieldSince: make(map[string]map[string]string),
|
||||
}
|
||||
vp.res[row.pkg] = pkgi
|
||||
}
|
||||
switch row.kind {
|
||||
case "func":
|
||||
pkgi.funcSince[row.name] = ver
|
||||
case "type":
|
||||
pkgi.typeSince[row.name] = ver
|
||||
case "method":
|
||||
if _, ok := pkgi.methodSince[row.recv]; !ok {
|
||||
pkgi.methodSince[row.recv] = make(map[string]string)
|
||||
}
|
||||
pkgi.methodSince[row.recv][row.name] = ver
|
||||
case "field":
|
||||
if _, ok := pkgi.fieldSince[row.structName]; !ok {
|
||||
pkgi.fieldSince[row.structName] = make(map[string]string)
|
||||
}
|
||||
pkgi.fieldSince[row.structName][row.name] = ver
|
||||
}
|
||||
}
|
||||
return sc.Err()
|
||||
}
|
||||
|
||||
func parseRow(s string) (vr versionedRow, ok bool) {
|
||||
if !strings.HasPrefix(s, "pkg ") {
|
||||
// Skip comments, blank lines, etc.
|
||||
return
|
||||
}
|
||||
rest := s[len("pkg "):]
|
||||
endPkg := strings.IndexFunc(rest, func(r rune) bool { return !(unicode.IsLetter(r) || r == '/' || unicode.IsDigit(r)) })
|
||||
if endPkg == -1 {
|
||||
return
|
||||
}
|
||||
vr.pkg, rest = rest[:endPkg], rest[endPkg:]
|
||||
if !strings.HasPrefix(rest, ", ") {
|
||||
// If the part after the pkg name isn't ", ", then it's a OS/ARCH-dependent line of the form:
|
||||
// pkg syscall (darwin-amd64), const ImplementsGetwd = false
|
||||
// We skip those for now.
|
||||
return
|
||||
}
|
||||
rest = rest[len(", "):]
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(rest, "type "):
|
||||
rest = rest[len("type "):]
|
||||
sp := strings.IndexByte(rest, ' ')
|
||||
if sp == -1 {
|
||||
return
|
||||
}
|
||||
vr.name, rest = rest[:sp], rest[sp+1:]
|
||||
if !strings.HasPrefix(rest, "struct, ") {
|
||||
vr.kind = "type"
|
||||
return vr, true
|
||||
}
|
||||
rest = rest[len("struct, "):]
|
||||
if i := strings.IndexByte(rest, ' '); i != -1 {
|
||||
vr.kind = "field"
|
||||
vr.structName = vr.name
|
||||
vr.name = rest[:i]
|
||||
return vr, true
|
||||
}
|
||||
case strings.HasPrefix(rest, "func "):
|
||||
vr.kind = "func"
|
||||
rest = rest[len("func "):]
|
||||
if i := strings.IndexByte(rest, '('); i != -1 {
|
||||
vr.name = rest[:i]
|
||||
return vr, true
|
||||
}
|
||||
case strings.HasPrefix(rest, "method "): // "method (*File) SetModTime(time.Time)"
|
||||
vr.kind = "method"
|
||||
rest = rest[len("method "):] // "(*File) SetModTime(time.Time)"
|
||||
sp := strings.IndexByte(rest, ' ')
|
||||
if sp == -1 {
|
||||
return
|
||||
}
|
||||
vr.recv = strings.Trim(rest[:sp], "()") // "*File"
|
||||
rest = rest[sp+1:] // SetMode(os.FileMode)
|
||||
paren := strings.IndexByte(rest, '(')
|
||||
if paren == -1 {
|
||||
return
|
||||
}
|
||||
vr.name = rest[:paren]
|
||||
return vr, true
|
||||
}
|
||||
return // TODO: handle more cases
|
||||
}
|
||||
|
||||
// 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 = parsePackageAPIInfo()
|
||||
if err != nil {
|
||||
// TODO: consider making this fatal, after the Go 1.11 cycle.
|
||||
log.Printf("godoc: error parsing API version files: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func parsePackageAPIInfo() (apiVersions, 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vp := new(versionParser)
|
||||
for _, f := range files {
|
||||
if err := vp.parseFile(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return vp.res, nil
|
||||
}
|
132
vendor/golang.org/x/tools/godoc/versions_test.go
generated
vendored
Normal file
132
vendor/golang.org/x/tools/godoc/versions_test.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
// 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.
|
||||
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"go/build"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseVersionRow(t *testing.T) {
|
||||
tests := []struct {
|
||||
row string
|
||||
want versionedRow
|
||||
}{
|
||||
{
|
||||
row: "# comment",
|
||||
},
|
||||
{
|
||||
row: "",
|
||||
},
|
||||
{
|
||||
row: "pkg archive/tar, type Writer struct",
|
||||
want: versionedRow{
|
||||
pkg: "archive/tar",
|
||||
kind: "type",
|
||||
name: "Writer",
|
||||
},
|
||||
},
|
||||
{
|
||||
row: "pkg archive/tar, type Header struct, AccessTime time.Time",
|
||||
want: versionedRow{
|
||||
pkg: "archive/tar",
|
||||
kind: "field",
|
||||
structName: "Header",
|
||||
name: "AccessTime",
|
||||
},
|
||||
},
|
||||
{
|
||||
row: "pkg archive/tar, method (*Reader) Read([]uint8) (int, error)",
|
||||
want: versionedRow{
|
||||
pkg: "archive/tar",
|
||||
kind: "method",
|
||||
name: "Read",
|
||||
recv: "*Reader",
|
||||
},
|
||||
},
|
||||
{
|
||||
row: "pkg archive/zip, func FileInfoHeader(os.FileInfo) (*FileHeader, error)",
|
||||
want: versionedRow{
|
||||
pkg: "archive/zip",
|
||||
kind: "func",
|
||||
name: "FileInfoHeader",
|
||||
},
|
||||
},
|
||||
{
|
||||
row: "pkg encoding/base32, method (Encoding) WithPadding(int32) *Encoding",
|
||||
want: versionedRow{
|
||||
pkg: "encoding/base32",
|
||||
kind: "method",
|
||||
name: "WithPadding",
|
||||
recv: "Encoding",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
got, ok := parseRow(tt.row)
|
||||
if !ok {
|
||||
got = versionedRow{}
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("%d. parseRow(%q) = %+v; want %+v", i, tt.row, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hasTag checks whether a given release tag is contained in the current version
|
||||
// of the go binary.
|
||||
func hasTag(t string) bool {
|
||||
for _, v := range build.Default.ReleaseTags {
|
||||
if t == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestAPIVersion(t *testing.T) {
|
||||
av, err := parsePackageAPIInfo()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
kind string
|
||||
pkg string
|
||||
name string
|
||||
receiver string
|
||||
want string
|
||||
}{
|
||||
// Things that were added post-1.0 should appear
|
||||
{"func", "archive/tar", "FileInfoHeader", "", "1.1"},
|
||||
{"type", "bufio", "Scanner", "", "1.1"},
|
||||
{"method", "bufio", "WriteTo", "*Reader", "1.1"},
|
||||
|
||||
{"func", "bytes", "LastIndexByte", "", "1.5"},
|
||||
{"type", "crypto", "Decrypter", "", "1.5"},
|
||||
{"method", "crypto/rsa", "Decrypt", "*PrivateKey", "1.5"},
|
||||
{"method", "debug/dwarf", "GoString", "Class", "1.5"},
|
||||
|
||||
{"func", "os", "IsTimeout", "", "1.10"},
|
||||
{"type", "strings", "Builder", "", "1.10"},
|
||||
{"method", "strings", "WriteString", "*Builder", "1.10"},
|
||||
|
||||
// Things from package syscall should never appear
|
||||
{"func", "syscall", "FchFlags", "", ""},
|
||||
{"type", "syscall", "Inet4Pktinfo", "", ""},
|
||||
|
||||
// Things added in Go 1 should never appear
|
||||
{"func", "archive/tar", "NewReader", "", ""},
|
||||
{"type", "archive/tar", "Header", "", ""},
|
||||
{"method", "archive/tar", "Next", "*Reader", ""},
|
||||
} {
|
||||
if tc.want != "" && !hasTag("go"+tc.want) {
|
||||
continue
|
||||
}
|
||||
if got := av.sinceVersionFunc(tc.kind, tc.receiver, tc.name, tc.pkg); got != tc.want {
|
||||
t.Errorf(`sinceFunc("%s", "%s", "%s", "%s") = "%s"; want "%s"`, tc.kind, tc.receiver, tc.name, tc.pkg, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
10
vendor/golang.org/x/tools/godoc/vfs/os.go
generated
vendored
10
vendor/golang.org/x/tools/godoc/vfs/os.go
generated
vendored
@@ -14,6 +14,14 @@ import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// We expose a new variable because otherwise we need to copy the findGOROOT logic again
|
||||
// from cmd/godoc which is already copied twice from the standard library.
|
||||
|
||||
// GOROOT is the GOROOT path under which the godoc binary is running.
|
||||
// It is needed to check whether a filesystem root is under GOROOT or not.
|
||||
// This is set from cmd/godoc/main.go.
|
||||
var GOROOT = runtime.GOROOT()
|
||||
|
||||
// OS returns an implementation of FileSystem reading from the
|
||||
// tree rooted at root. Recording a root is convenient everywhere
|
||||
// but necessary on Windows, because the slash-separated path
|
||||
@@ -22,7 +30,7 @@ import (
|
||||
func OS(root string) FileSystem {
|
||||
var t RootType
|
||||
switch {
|
||||
case root == runtime.GOROOT():
|
||||
case root == GOROOT:
|
||||
t = RootTypeGoRoot
|
||||
case isGoPath(root):
|
||||
t = RootTypeGoPath
|
||||
|
12
vendor/golang.org/x/tools/godoc/vfs/zipfs/zipfs.go
generated
vendored
12
vendor/golang.org/x/tools/godoc/vfs/zipfs/zipfs.go
generated
vendored
@@ -25,7 +25,6 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -87,7 +86,7 @@ func (fs *zipFS) String() string {
|
||||
func (fs *zipFS) RootType(abspath string) vfs.RootType {
|
||||
var t vfs.RootType
|
||||
switch {
|
||||
case abspath == runtime.GOROOT():
|
||||
case exists(path.Join(vfs.GOROOT, abspath)):
|
||||
t = vfs.RootTypeGoRoot
|
||||
case isGoPath(abspath):
|
||||
t = vfs.RootTypeGoPath
|
||||
@@ -95,15 +94,20 @@ func (fs *zipFS) RootType(abspath string) vfs.RootType {
|
||||
return t
|
||||
}
|
||||
|
||||
func isGoPath(path string) bool {
|
||||
func isGoPath(abspath string) bool {
|
||||
for _, p := range filepath.SplitList(build.Default.GOPATH) {
|
||||
if p == path {
|
||||
if exists(path.Join(p, abspath)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func exists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (fs *zipFS) Close() error {
|
||||
fs.list = nil
|
||||
return fs.ReadCloser.Close()
|
||||
|
17
vendor/golang.org/x/tools/godoc/vfs/zipfs/zipfs_test.go
generated
vendored
17
vendor/golang.org/x/tools/godoc/vfs/zipfs/zipfs_test.go
generated
vendored
@@ -187,3 +187,20 @@ func TestZipFSOpenSeek(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRootType(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
fsType vfs.RootType
|
||||
}{
|
||||
{"/src/net/http", vfs.RootTypeGoRoot},
|
||||
{"/src/badpath", ""},
|
||||
{"/", vfs.RootTypeGoRoot},
|
||||
}
|
||||
|
||||
for _, item := range tests {
|
||||
if fs.RootType(item.path) != item.fsType {
|
||||
t.Errorf("unexpected fsType. Expected- %v, Got- %v", item.fsType, fs.RootType(item.path))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user