Add generated file
This PR adds generated files under pkg/client and vendor folder.
This commit is contained in:
56
vendor/golang.org/x/tools/cmd/godoc/README.godoc-app
generated
vendored
Normal file
56
vendor/golang.org/x/tools/cmd/godoc/README.godoc-app
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
godoc on appengine
|
||||
------------------
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
* Go appengine SDK
|
||||
https://developers.google.com/appengine/downloads#Google_App_Engine_SDK_for_Go
|
||||
|
||||
* Go sources at tip under $GOROOT
|
||||
|
||||
* Godoc sources at tip inside $GOPATH
|
||||
(go get -d golang.org/x/tools/cmd/godoc)
|
||||
|
||||
|
||||
Directory structure
|
||||
-------------------
|
||||
|
||||
* Let $APPDIR be the directory containing the app engine files.
|
||||
(e.g., $APPDIR=$HOME/godoc-app)
|
||||
|
||||
* $APPDIR contains the following entries (this may change depending on
|
||||
app-engine release and version of godoc):
|
||||
|
||||
app.yaml
|
||||
golang.org/x/tools/cmd/godoc
|
||||
godoc.zip
|
||||
index.split.*
|
||||
|
||||
* The app.yaml file is set up per app engine documentation.
|
||||
For instance:
|
||||
|
||||
application: godoc-app
|
||||
version: 1
|
||||
runtime: go
|
||||
api_version: go1
|
||||
|
||||
handlers:
|
||||
- url: /.*
|
||||
script: _go_app
|
||||
|
||||
|
||||
Configuring and running godoc
|
||||
-----------------------------
|
||||
|
||||
To configure godoc, run
|
||||
|
||||
bash setup-godoc-app.bash
|
||||
|
||||
to prepare an $APPDIR as described above. See the script for details on usage.
|
||||
|
||||
To run godoc locally, using the App Engine development server, run
|
||||
|
||||
<path to go_appengine>/dev_appserver.py $APPDIR
|
||||
|
||||
godoc should come up at http://localhost:8080 .
|
82
vendor/golang.org/x/tools/cmd/godoc/appinit.go
generated
vendored
Normal file
82
vendor/golang.org/x/tools/cmd/godoc/appinit.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2011 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 main
|
||||
|
||||
// This file replaces main.go when running godoc under app-engine.
|
||||
// See README.godoc-app for details.
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"log"
|
||||
"net/http"
|
||||
"path"
|
||||
"regexp"
|
||||
|
||||
"golang.org/x/tools/godoc"
|
||||
"golang.org/x/tools/godoc/dl"
|
||||
"golang.org/x/tools/godoc/proxy"
|
||||
"golang.org/x/tools/godoc/short"
|
||||
"golang.org/x/tools/godoc/static"
|
||||
"golang.org/x/tools/godoc/vfs"
|
||||
"golang.org/x/tools/godoc/vfs/mapfs"
|
||||
"golang.org/x/tools/godoc/vfs/zipfs"
|
||||
|
||||
"google.golang.org/appengine"
|
||||
)
|
||||
|
||||
func init() {
|
||||
enforceHosts = !appengine.IsDevAppServer()
|
||||
playEnabled = true
|
||||
|
||||
log.Println("initializing godoc ...")
|
||||
log.Printf(".zip file = %s", zipFilename)
|
||||
log.Printf(".zip GOROOT = %s", zipGoroot)
|
||||
log.Printf("index files = %s", indexFilenames)
|
||||
|
||||
goroot := path.Join("/", zipGoroot) // fsHttp paths are relative to '/'
|
||||
|
||||
// read .zip file and set up file systems
|
||||
const zipfile = zipFilename
|
||||
rc, err := zip.OpenReader(zipfile)
|
||||
if err != nil {
|
||||
log.Fatalf("%s: %s\n", zipfile, err)
|
||||
}
|
||||
// rc is never closed (app running forever)
|
||||
fs.Bind("/", zipfs.New(rc, zipFilename), goroot, vfs.BindReplace)
|
||||
fs.Bind("/lib/godoc", mapfs.New(static.Files), "/", vfs.BindReplace)
|
||||
|
||||
corpus := godoc.NewCorpus(fs)
|
||||
corpus.Verbose = false
|
||||
corpus.MaxResults = 10000 // matches flag default in main.go
|
||||
corpus.IndexEnabled = true
|
||||
corpus.IndexFiles = indexFilenames
|
||||
if err := corpus.Init(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
corpus.IndexDirectory = indexDirectoryDefault
|
||||
go corpus.RunIndexer()
|
||||
|
||||
pres = godoc.NewPresentation(corpus)
|
||||
pres.TabWidth = 8
|
||||
pres.ShowPlayground = true
|
||||
pres.ShowExamples = true
|
||||
pres.DeclLinks = true
|
||||
pres.NotesRx = regexp.MustCompile("BUG")
|
||||
|
||||
readTemplates(pres, true)
|
||||
|
||||
mux := registerHandlers(pres)
|
||||
dl.RegisterHandlers(mux)
|
||||
short.RegisterHandlers(mux)
|
||||
|
||||
// Register /compile and /share handlers against the default serve mux
|
||||
// so that other app modules can make plain HTTP requests to those
|
||||
// hosts. (For reasons, HTTPS communication between modules is broken.)
|
||||
proxy.RegisterHandlers(http.DefaultServeMux)
|
||||
|
||||
log.Println("godoc initialization complete")
|
||||
}
|
88
vendor/golang.org/x/tools/cmd/godoc/autocert.go
generated
vendored
Normal file
88
vendor/golang.org/x/tools/cmd/godoc/autocert.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright 2016 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 autocert
|
||||
|
||||
// This file adds automatic TLS certificate support (using
|
||||
// golang.org/x/crypto/acme/autocert), conditional on the use of the
|
||||
// autocert build tag. It sets the serveAutoCertHook func variable
|
||||
// non-nil. It is used by main.go.
|
||||
//
|
||||
// TODO: make this the default? We're in the Go 1.8 freeze now, so
|
||||
// this is too invasive to be default, but we want it for
|
||||
// https://beta.golang.org/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
var (
|
||||
autoCertDirFlag = flag.String("autocert_cache_dir", "/var/cache/autocert", "Directory to cache TLS certs")
|
||||
autoCertHostFlag = flag.String("autocert_hostname", "", "optional hostname to require in autocert SNI requests")
|
||||
)
|
||||
|
||||
func init() {
|
||||
runHTTPS = runHTTPSAutocert
|
||||
certInit = certInitAutocert
|
||||
wrapHTTPMux = wrapHTTPMuxAutocert
|
||||
}
|
||||
|
||||
var autocertManager *autocert.Manager
|
||||
|
||||
func certInitAutocert() {
|
||||
autocertManager = &autocert.Manager{
|
||||
Cache: autocert.DirCache(*autoCertDirFlag),
|
||||
Prompt: autocert.AcceptTOS,
|
||||
}
|
||||
if *autoCertHostFlag != "" {
|
||||
autocertManager.HostPolicy = autocert.HostWhitelist(*autoCertHostFlag)
|
||||
}
|
||||
}
|
||||
|
||||
func runHTTPSAutocert(h http.Handler) error {
|
||||
srv := &http.Server{
|
||||
Handler: h,
|
||||
TLSConfig: &tls.Config{
|
||||
GetCertificate: autocertManager.GetCertificate,
|
||||
},
|
||||
IdleTimeout: 60 * time.Second,
|
||||
}
|
||||
http2.ConfigureServer(srv, &http2.Server{})
|
||||
ln, err := net.Listen("tcp", ":443")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.Serve(tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, srv.TLSConfig))
|
||||
}
|
||||
|
||||
func wrapHTTPMuxAutocert(h http.Handler) http.Handler {
|
||||
return autocertManager.HTTPHandler(h)
|
||||
}
|
||||
|
||||
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
|
||||
// connections. It's used by ListenAndServe and ListenAndServeTLS so
|
||||
// dead TCP connections (e.g. closing laptop mid-download) eventually
|
||||
// go away.
|
||||
type tcpKeepAliveListener struct {
|
||||
*net.TCPListener
|
||||
}
|
||||
|
||||
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
|
||||
tc, err := ln.AcceptTCP()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tc.SetKeepAlive(true)
|
||||
tc.SetKeepAlivePeriod(3 * time.Minute)
|
||||
return tc, nil
|
||||
}
|
84
vendor/golang.org/x/tools/cmd/godoc/blog.go
generated
vendored
Normal file
84
vendor/golang.org/x/tools/cmd/godoc/blog.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/tools/blog"
|
||||
"golang.org/x/tools/godoc/redirect"
|
||||
)
|
||||
|
||||
const (
|
||||
blogRepo = "golang.org/x/blog"
|
||||
blogURL = "http://blog.golang.org/"
|
||||
blogPath = "/blog/"
|
||||
)
|
||||
|
||||
var (
|
||||
blogServer http.Handler // set by blogInit
|
||||
blogInitOnce sync.Once
|
||||
playEnabled bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Initialize blog only when first accessed.
|
||||
http.HandleFunc(blogPath, func(w http.ResponseWriter, r *http.Request) {
|
||||
blogInitOnce.Do(func() {
|
||||
blogInit(r.Host)
|
||||
})
|
||||
blogServer.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func blogInit(host string) {
|
||||
// Binary distributions will include the blog content in "/blog".
|
||||
root := filepath.Join(runtime.GOROOT(), "blog")
|
||||
|
||||
// Prefer content from go.blog repository if present.
|
||||
if pkg, err := build.Import(blogRepo, "", build.FindOnly); err == nil {
|
||||
root = pkg.Dir
|
||||
}
|
||||
|
||||
// If content is not available fall back to redirect.
|
||||
if fi, err := os.Stat(root); err != nil || !fi.IsDir() {
|
||||
fmt.Fprintf(os.Stderr, "Blog content not available locally. "+
|
||||
"To install, run \n\tgo get %v\n", blogRepo)
|
||||
blogServer = http.HandlerFunc(blogRedirectHandler)
|
||||
return
|
||||
}
|
||||
|
||||
s, err := blog.NewServer(blog.Config{
|
||||
BaseURL: blogPath,
|
||||
BasePath: strings.TrimSuffix(blogPath, "/"),
|
||||
ContentPath: filepath.Join(root, "content"),
|
||||
TemplatePath: filepath.Join(root, "template"),
|
||||
HomeArticles: 5,
|
||||
PlayEnabled: playEnabled,
|
||||
ServeLocalLinks: strings.HasPrefix(host, "localhost"),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
blogServer = s
|
||||
}
|
||||
|
||||
func blogRedirectHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == blogPath {
|
||||
http.Redirect(w, r, blogURL, http.StatusFound)
|
||||
return
|
||||
}
|
||||
blogPrefixHandler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
var blogPrefixHandler = redirect.PrefixHandler(blogPath, blogURL)
|
523
vendor/golang.org/x/tools/cmd/godoc/codewalk.go
generated
vendored
Normal file
523
vendor/golang.org/x/tools/cmd/godoc/codewalk.go
generated
vendored
Normal file
@@ -0,0 +1,523 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
// The /doc/codewalk/ tree is synthesized from codewalk descriptions,
|
||||
// files named $GOROOT/doc/codewalk/*.xml.
|
||||
// For an example and a description of the format, see
|
||||
// http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060
|
||||
// and see http://localhost:6060/doc/codewalk/codewalk .
|
||||
// That page is itself a codewalk; the source code for it is
|
||||
// $GOROOT/doc/codewalk/codewalk.xml.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
pathpkg "path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/tools/godoc"
|
||||
"golang.org/x/tools/godoc/vfs"
|
||||
)
|
||||
|
||||
var codewalkHTML, codewalkdirHTML *template.Template
|
||||
|
||||
// Handler for /doc/codewalk/ and below.
|
||||
func codewalk(w http.ResponseWriter, r *http.Request) {
|
||||
relpath := r.URL.Path[len("/doc/codewalk/"):]
|
||||
abspath := r.URL.Path
|
||||
|
||||
r.ParseForm()
|
||||
if f := r.FormValue("fileprint"); f != "" {
|
||||
codewalkFileprint(w, r, f)
|
||||
return
|
||||
}
|
||||
|
||||
// If directory exists, serve list of code walks.
|
||||
dir, err := fs.Lstat(abspath)
|
||||
if err == nil && dir.IsDir() {
|
||||
codewalkDir(w, r, relpath, abspath)
|
||||
return
|
||||
}
|
||||
|
||||
// If file exists, serve using standard file server.
|
||||
if err == nil {
|
||||
pres.ServeFile(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise append .xml and hope to find
|
||||
// a codewalk description, but before trim
|
||||
// the trailing /.
|
||||
abspath = strings.TrimRight(abspath, "/")
|
||||
cw, err := loadCodewalk(abspath + ".xml")
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
pres.ServeError(w, r, relpath, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Canonicalize the path and redirect if changed
|
||||
if redir(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
pres.ServePage(w, godoc.Page{
|
||||
Title: "Codewalk: " + cw.Title,
|
||||
Tabtitle: cw.Title,
|
||||
Body: applyTemplate(codewalkHTML, "codewalk", cw),
|
||||
})
|
||||
}
|
||||
|
||||
func redir(w http.ResponseWriter, r *http.Request) (redirected bool) {
|
||||
canonical := pathpkg.Clean(r.URL.Path)
|
||||
if !strings.HasSuffix(canonical, "/") {
|
||||
canonical += "/"
|
||||
}
|
||||
if r.URL.Path != canonical {
|
||||
url := *r.URL
|
||||
url.Path = canonical
|
||||
http.Redirect(w, r, url.String(), http.StatusMovedPermanently)
|
||||
redirected = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func applyTemplate(t *template.Template, name string, data interface{}) []byte {
|
||||
var buf bytes.Buffer
|
||||
if err := t.Execute(&buf, data); err != nil {
|
||||
log.Printf("%s.Execute: %s", name, err)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// A Codewalk represents a single codewalk read from an XML file.
|
||||
type Codewalk struct {
|
||||
Title string `xml:"title,attr"`
|
||||
File []string `xml:"file"`
|
||||
Step []*Codestep `xml:"step"`
|
||||
}
|
||||
|
||||
// A Codestep is a single step in a codewalk.
|
||||
type Codestep struct {
|
||||
// Filled in from XML
|
||||
Src string `xml:"src,attr"`
|
||||
Title string `xml:"title,attr"`
|
||||
XML string `xml:",innerxml"`
|
||||
|
||||
// Derived from Src; not in XML.
|
||||
Err error
|
||||
File string
|
||||
Lo int
|
||||
LoByte int
|
||||
Hi int
|
||||
HiByte int
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// String method for printing in template.
|
||||
// Formats file address nicely.
|
||||
func (st *Codestep) String() string {
|
||||
s := st.File
|
||||
if st.Lo != 0 || st.Hi != 0 {
|
||||
s += fmt.Sprintf(":%d", st.Lo)
|
||||
if st.Lo != st.Hi {
|
||||
s += fmt.Sprintf(",%d", st.Hi)
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// loadCodewalk reads a codewalk from the named XML file.
|
||||
func loadCodewalk(filename string) (*Codewalk, error) {
|
||||
f, err := fs.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
cw := new(Codewalk)
|
||||
d := xml.NewDecoder(f)
|
||||
d.Entity = xml.HTMLEntity
|
||||
err = d.Decode(cw)
|
||||
if err != nil {
|
||||
return nil, &os.PathError{Op: "parsing", Path: filename, Err: err}
|
||||
}
|
||||
|
||||
// Compute file list, evaluate line numbers for addresses.
|
||||
m := make(map[string]bool)
|
||||
for _, st := range cw.Step {
|
||||
i := strings.Index(st.Src, ":")
|
||||
if i < 0 {
|
||||
i = len(st.Src)
|
||||
}
|
||||
filename := st.Src[0:i]
|
||||
data, err := vfs.ReadFile(fs, filename)
|
||||
if err != nil {
|
||||
st.Err = err
|
||||
continue
|
||||
}
|
||||
if i < len(st.Src) {
|
||||
lo, hi, err := addrToByteRange(st.Src[i+1:], 0, data)
|
||||
if err != nil {
|
||||
st.Err = err
|
||||
continue
|
||||
}
|
||||
// Expand match to line boundaries.
|
||||
for lo > 0 && data[lo-1] != '\n' {
|
||||
lo--
|
||||
}
|
||||
for hi < len(data) && (hi == 0 || data[hi-1] != '\n') {
|
||||
hi++
|
||||
}
|
||||
st.Lo = byteToLine(data, lo)
|
||||
st.Hi = byteToLine(data, hi-1)
|
||||
}
|
||||
st.Data = data
|
||||
st.File = filename
|
||||
m[filename] = true
|
||||
}
|
||||
|
||||
// Make list of files
|
||||
cw.File = make([]string, len(m))
|
||||
i := 0
|
||||
for f := range m {
|
||||
cw.File[i] = f
|
||||
i++
|
||||
}
|
||||
sort.Strings(cw.File)
|
||||
|
||||
return cw, nil
|
||||
}
|
||||
|
||||
// codewalkDir serves the codewalk directory listing.
|
||||
// It scans the directory for subdirectories or files named *.xml
|
||||
// and prepares a table.
|
||||
func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string) {
|
||||
type elem struct {
|
||||
Name string
|
||||
Title string
|
||||
}
|
||||
|
||||
dir, err := fs.ReadDir(abspath)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
pres.ServeError(w, r, relpath, err)
|
||||
return
|
||||
}
|
||||
var v []interface{}
|
||||
for _, fi := range dir {
|
||||
name := fi.Name()
|
||||
if fi.IsDir() {
|
||||
v = append(v, &elem{name + "/", ""})
|
||||
} else if strings.HasSuffix(name, ".xml") {
|
||||
cw, err := loadCodewalk(abspath + "/" + name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
v = append(v, &elem{name[0 : len(name)-len(".xml")], cw.Title})
|
||||
}
|
||||
}
|
||||
|
||||
pres.ServePage(w, godoc.Page{
|
||||
Title: "Codewalks",
|
||||
Body: applyTemplate(codewalkdirHTML, "codewalkdir", v),
|
||||
})
|
||||
}
|
||||
|
||||
// codewalkFileprint serves requests with ?fileprint=f&lo=lo&hi=hi.
|
||||
// The filename f has already been retrieved and is passed as an argument.
|
||||
// Lo and hi are the numbers of the first and last line to highlight
|
||||
// in the response. This format is used for the middle window pane
|
||||
// of the codewalk pages. It is a separate iframe and does not get
|
||||
// the usual godoc HTML wrapper.
|
||||
func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
|
||||
abspath := f
|
||||
data, err := vfs.ReadFile(fs, abspath)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
pres.ServeError(w, r, f, err)
|
||||
return
|
||||
}
|
||||
lo, _ := strconv.Atoi(r.FormValue("lo"))
|
||||
hi, _ := strconv.Atoi(r.FormValue("hi"))
|
||||
if hi < lo {
|
||||
hi = lo
|
||||
}
|
||||
lo = lineToByte(data, lo)
|
||||
hi = lineToByte(data, hi+1)
|
||||
|
||||
// Put the mark 4 lines before lo, so that the iframe
|
||||
// shows a few lines of context before the highlighted
|
||||
// section.
|
||||
n := 4
|
||||
mark := lo
|
||||
for ; mark > 0 && n > 0; mark-- {
|
||||
if data[mark-1] == '\n' {
|
||||
if n--; n == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
io.WriteString(w, `<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`)
|
||||
template.HTMLEscape(w, data[0:mark])
|
||||
io.WriteString(w, "<a name='mark'></a>")
|
||||
template.HTMLEscape(w, data[mark:lo])
|
||||
if lo < hi {
|
||||
io.WriteString(w, "<div class='codewalkhighlight'>")
|
||||
template.HTMLEscape(w, data[lo:hi])
|
||||
io.WriteString(w, "</div>")
|
||||
}
|
||||
template.HTMLEscape(w, data[hi:])
|
||||
io.WriteString(w, "</pre>")
|
||||
}
|
||||
|
||||
// addrToByte evaluates the given address starting at offset start in data.
|
||||
// It returns the lo and hi byte offset of the matched region within data.
|
||||
// See http://plan9.bell-labs.com/sys/doc/sam/sam.html Table II
|
||||
// for details on the syntax.
|
||||
func addrToByteRange(addr string, start int, data []byte) (lo, hi int, err error) {
|
||||
var (
|
||||
dir byte
|
||||
prevc byte
|
||||
charOffset bool
|
||||
)
|
||||
lo = start
|
||||
hi = start
|
||||
for addr != "" && err == nil {
|
||||
c := addr[0]
|
||||
switch c {
|
||||
default:
|
||||
err = errors.New("invalid address syntax near " + string(c))
|
||||
case ',':
|
||||
if len(addr) == 1 {
|
||||
hi = len(data)
|
||||
} else {
|
||||
_, hi, err = addrToByteRange(addr[1:], hi, data)
|
||||
}
|
||||
return
|
||||
|
||||
case '+', '-':
|
||||
if prevc == '+' || prevc == '-' {
|
||||
lo, hi, err = addrNumber(data, lo, hi, prevc, 1, charOffset)
|
||||
}
|
||||
dir = c
|
||||
|
||||
case '$':
|
||||
lo = len(data)
|
||||
hi = len(data)
|
||||
if len(addr) > 1 {
|
||||
dir = '+'
|
||||
}
|
||||
|
||||
case '#':
|
||||
charOffset = true
|
||||
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
var i int
|
||||
for i = 1; i < len(addr); i++ {
|
||||
if addr[i] < '0' || addr[i] > '9' {
|
||||
break
|
||||
}
|
||||
}
|
||||
var n int
|
||||
n, err = strconv.Atoi(addr[0:i])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
lo, hi, err = addrNumber(data, lo, hi, dir, n, charOffset)
|
||||
dir = 0
|
||||
charOffset = false
|
||||
prevc = c
|
||||
addr = addr[i:]
|
||||
continue
|
||||
|
||||
case '/':
|
||||
var i, j int
|
||||
Regexp:
|
||||
for i = 1; i < len(addr); i++ {
|
||||
switch addr[i] {
|
||||
case '\\':
|
||||
i++
|
||||
case '/':
|
||||
j = i + 1
|
||||
break Regexp
|
||||
}
|
||||
}
|
||||
if j == 0 {
|
||||
j = i
|
||||
}
|
||||
pattern := addr[1:i]
|
||||
lo, hi, err = addrRegexp(data, lo, hi, dir, pattern)
|
||||
prevc = c
|
||||
addr = addr[j:]
|
||||
continue
|
||||
}
|
||||
prevc = c
|
||||
addr = addr[1:]
|
||||
}
|
||||
|
||||
if err == nil && dir != 0 {
|
||||
lo, hi, err = addrNumber(data, lo, hi, dir, 1, charOffset)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
return lo, hi, nil
|
||||
}
|
||||
|
||||
// addrNumber applies the given dir, n, and charOffset to the address lo, hi.
|
||||
// dir is '+' or '-', n is the count, and charOffset is true if the syntax
|
||||
// used was #n. Applying +n (or +#n) means to advance n lines
|
||||
// (or characters) after hi. Applying -n (or -#n) means to back up n lines
|
||||
// (or characters) before lo.
|
||||
// The return value is the new lo, hi.
|
||||
func addrNumber(data []byte, lo, hi int, dir byte, n int, charOffset bool) (int, int, error) {
|
||||
switch dir {
|
||||
case 0:
|
||||
lo = 0
|
||||
hi = 0
|
||||
fallthrough
|
||||
|
||||
case '+':
|
||||
if charOffset {
|
||||
pos := hi
|
||||
for ; n > 0 && pos < len(data); n-- {
|
||||
_, size := utf8.DecodeRune(data[pos:])
|
||||
pos += size
|
||||
}
|
||||
if n == 0 {
|
||||
return pos, pos, nil
|
||||
}
|
||||
break
|
||||
}
|
||||
// find next beginning of line
|
||||
if hi > 0 {
|
||||
for hi < len(data) && data[hi-1] != '\n' {
|
||||
hi++
|
||||
}
|
||||
}
|
||||
lo = hi
|
||||
if n == 0 {
|
||||
return lo, hi, nil
|
||||
}
|
||||
for ; hi < len(data); hi++ {
|
||||
if data[hi] != '\n' {
|
||||
continue
|
||||
}
|
||||
switch n--; n {
|
||||
case 1:
|
||||
lo = hi + 1
|
||||
case 0:
|
||||
return lo, hi + 1, nil
|
||||
}
|
||||
}
|
||||
|
||||
case '-':
|
||||
if charOffset {
|
||||
// Scan backward for bytes that are not UTF-8 continuation bytes.
|
||||
pos := lo
|
||||
for ; pos > 0 && n > 0; pos-- {
|
||||
if data[pos]&0xc0 != 0x80 {
|
||||
n--
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
return pos, pos, nil
|
||||
}
|
||||
break
|
||||
}
|
||||
// find earlier beginning of line
|
||||
for lo > 0 && data[lo-1] != '\n' {
|
||||
lo--
|
||||
}
|
||||
hi = lo
|
||||
if n == 0 {
|
||||
return lo, hi, nil
|
||||
}
|
||||
for ; lo >= 0; lo-- {
|
||||
if lo > 0 && data[lo-1] != '\n' {
|
||||
continue
|
||||
}
|
||||
switch n--; n {
|
||||
case 1:
|
||||
hi = lo
|
||||
case 0:
|
||||
return lo, hi, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0, 0, errors.New("address out of range")
|
||||
}
|
||||
|
||||
// addrRegexp searches for pattern in the given direction starting at lo, hi.
|
||||
// The direction dir is '+' (search forward from hi) or '-' (search backward from lo).
|
||||
// Backward searches are unimplemented.
|
||||
func addrRegexp(data []byte, lo, hi int, dir byte, pattern string) (int, int, error) {
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
if dir == '-' {
|
||||
// Could implement reverse search using binary search
|
||||
// through file, but that seems like overkill.
|
||||
return 0, 0, errors.New("reverse search not implemented")
|
||||
}
|
||||
m := re.FindIndex(data[hi:])
|
||||
if len(m) > 0 {
|
||||
m[0] += hi
|
||||
m[1] += hi
|
||||
} else if hi > 0 {
|
||||
// No match. Wrap to beginning of data.
|
||||
m = re.FindIndex(data)
|
||||
}
|
||||
if len(m) == 0 {
|
||||
return 0, 0, errors.New("no match for " + pattern)
|
||||
}
|
||||
return m[0], m[1], nil
|
||||
}
|
||||
|
||||
// lineToByte returns the byte index of the first byte of line n.
|
||||
// Line numbers begin at 1.
|
||||
func lineToByte(data []byte, n int) int {
|
||||
if n <= 1 {
|
||||
return 0
|
||||
}
|
||||
n--
|
||||
for i, c := range data {
|
||||
if c == '\n' {
|
||||
if n--; n == 0 {
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return len(data)
|
||||
}
|
||||
|
||||
// byteToLine returns the number of the line containing the byte at index i.
|
||||
func byteToLine(data []byte, i int) int {
|
||||
l := 1
|
||||
for j, c := range data {
|
||||
if j == i {
|
||||
return l
|
||||
}
|
||||
if c == '\n' {
|
||||
l++
|
||||
}
|
||||
}
|
||||
return l
|
||||
}
|
16
vendor/golang.org/x/tools/cmd/godoc/dl.go
generated
vendored
Normal file
16
vendor/golang.org/x/tools/cmd/godoc/dl.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2014 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 main
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Register a redirect handler for /dl/ to the golang.org download page.
|
||||
// This file will not be included when deploying godoc to golang.org.
|
||||
|
||||
func init() {
|
||||
http.Handle("/dl/", http.RedirectHandler("https://golang.org/dl/", http.StatusFound))
|
||||
}
|
153
vendor/golang.org/x/tools/cmd/godoc/doc.go
generated
vendored
Normal file
153
vendor/golang.org/x/tools/cmd/godoc/doc.go
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
/*
|
||||
|
||||
Godoc extracts and generates documentation for Go programs.
|
||||
|
||||
It has two modes.
|
||||
|
||||
Without the -http flag, it runs in command-line mode and prints plain text
|
||||
documentation to standard output and exits. If both a library package and
|
||||
a command with the same name exists, using the prefix cmd/ will force
|
||||
documentation on the command rather than the library package. If the -src
|
||||
flag is specified, godoc prints the exported interface of a package in Go
|
||||
source form, or the implementation of a specific exported language entity:
|
||||
|
||||
godoc fmt # documentation for package fmt
|
||||
godoc fmt Printf # documentation for fmt.Printf
|
||||
godoc cmd/go # force documentation for the go command
|
||||
godoc -src fmt # fmt package interface in Go source form
|
||||
godoc -src fmt Printf # implementation of fmt.Printf
|
||||
|
||||
In command-line mode, the -q flag enables search queries against a godoc running
|
||||
as a webserver. If no explicit server address is specified with the -server flag,
|
||||
godoc first tries localhost:6060 and then http://golang.org.
|
||||
|
||||
godoc -q Reader
|
||||
godoc -q math.Sin
|
||||
godoc -server=:6060 -q sin
|
||||
|
||||
With the -http flag, it runs as a web server and presents the documentation as a
|
||||
web page.
|
||||
|
||||
godoc -http=:6060
|
||||
|
||||
Usage:
|
||||
|
||||
godoc [flag] package [name ...]
|
||||
|
||||
The flags are:
|
||||
|
||||
-v
|
||||
verbose mode
|
||||
-q
|
||||
arguments are considered search queries: a legal query is a
|
||||
single identifier (such as ToLower) or a qualified identifier
|
||||
(such as math.Sin)
|
||||
-src
|
||||
print (exported) source in command-line mode
|
||||
-tabwidth=4
|
||||
width of tabs in units of spaces
|
||||
-timestamps=true
|
||||
show timestamps with directory listings
|
||||
-index
|
||||
enable identifier and full text search index
|
||||
(no search box is shown if -index is not set)
|
||||
-index_files=""
|
||||
glob pattern specifying index files; if not empty,
|
||||
the index is read from these files in sorted order
|
||||
-index_throttle=0.75
|
||||
index throttle value; a value of 0 means no time is allocated
|
||||
to the indexer (the indexer will never finish), a value of 1.0
|
||||
means that index creation is running at full throttle (other
|
||||
goroutines may get no time while the index is built)
|
||||
-links=true:
|
||||
link identifiers to their declarations
|
||||
-write_index=false
|
||||
write index to a file; the file name must be specified with
|
||||
-index_files
|
||||
-maxresults=10000
|
||||
maximum number of full text search results shown
|
||||
(no full text index is built if maxresults <= 0)
|
||||
-notes="BUG"
|
||||
regular expression matching note markers to show
|
||||
(e.g., "BUG|TODO", ".*")
|
||||
-html
|
||||
print HTML in command-line mode
|
||||
-goroot=$GOROOT
|
||||
Go root directory
|
||||
-http=addr
|
||||
HTTP service address (e.g., '127.0.0.1:6060' or just ':6060')
|
||||
-server=addr
|
||||
webserver address for command line searches
|
||||
-analysis=type,pointer
|
||||
comma-separated list of analyses to perform
|
||||
"type": display identifier resolution, type info, method sets,
|
||||
'implements', and static callees
|
||||
"pointer": display channel peers, callers and dynamic callees
|
||||
(significantly slower)
|
||||
See http://golang.org/lib/godoc/analysis/help.html for details.
|
||||
-templates=""
|
||||
directory containing alternate template files; if set,
|
||||
the directory may provide alternative template files
|
||||
for the files in $GOROOT/lib/godoc
|
||||
-url=path
|
||||
print to standard output the data that would be served by
|
||||
an HTTP request for path
|
||||
-zip=""
|
||||
zip file providing the file system to serve; disabled if empty
|
||||
|
||||
By default, godoc looks at the packages it finds via $GOROOT and $GOPATH (if set).
|
||||
This behavior can be altered by providing an alternative $GOROOT with the -goroot
|
||||
flag.
|
||||
|
||||
When godoc runs as a web server and -index is set, a search index is maintained.
|
||||
The index is created at startup.
|
||||
|
||||
The index contains both identifier and full text search information (searchable
|
||||
via regular expressions). The maximum number of full text search results shown
|
||||
can be set with the -maxresults flag; if set to 0, no full text results are
|
||||
shown, and only an identifier index but no full text search index is created.
|
||||
|
||||
By default, godoc uses the system's GOOS/GOARCH; in command-line mode you can
|
||||
set the GOOS/GOARCH environment variables to get output for the system specified.
|
||||
If -http was specified you can provide the URL parameters "GOOS" and "GOARCH"
|
||||
to set the output on the web page.
|
||||
|
||||
The presentation mode of web pages served by godoc can be controlled with the
|
||||
"m" URL parameter; it accepts a comma-separated list of flag names as value:
|
||||
|
||||
all show documentation for all declarations, not just the exported ones
|
||||
methods show all embedded methods, not just those of unexported anonymous fields
|
||||
src show the original source code rather then the extracted documentation
|
||||
text present the page in textual (command-line) form rather than HTML
|
||||
flat present flat (not indented) directory listings using full paths
|
||||
|
||||
For instance, http://golang.org/pkg/math/big/?m=all,text shows the documentation
|
||||
for all (not just the exported) declarations of package big, in textual form (as
|
||||
it would appear when using godoc from the command line: "godoc -src math/big .*").
|
||||
|
||||
By default, godoc serves files from the file system of the underlying OS.
|
||||
Instead, a .zip file may be provided via the -zip flag, which contains
|
||||
the file system to serve. The file paths stored in the .zip file must use
|
||||
slash ('/') as path separator; and they must be unrooted. $GOROOT (or -goroot)
|
||||
must be set to the .zip file directory path containing the Go root directory.
|
||||
For instance, for a .zip file created by the command:
|
||||
|
||||
zip -r go.zip $HOME/go
|
||||
|
||||
one may run godoc as follows:
|
||||
|
||||
godoc -http=:6060 -zip=go.zip -goroot=$HOME/go
|
||||
|
||||
Godoc documentation is converted to HTML or to text using the go/doc package;
|
||||
see http://golang.org/pkg/go/doc/#ToHTML for the exact rules.
|
||||
Godoc also shows example code that is runnable by the testing package;
|
||||
see http://golang.org/pkg/testing/#hdr-Examples for the conventions.
|
||||
See "Godoc: documenting Go code" for how to write good comments for godoc:
|
||||
http://golang.org/doc/articles/godoc_documenting_go_code.html
|
||||
|
||||
*/
|
||||
package main // import "golang.org/x/tools/cmd/godoc"
|
9
vendor/golang.org/x/tools/cmd/godoc/godoc19_test.go
generated
vendored
Normal file
9
vendor/golang.org/x/tools/cmd/godoc/godoc19_test.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright 2017 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 go1.9
|
||||
|
||||
package main_test
|
||||
|
||||
func init() { isGo19 = true }
|
477
vendor/golang.org/x/tools/cmd/godoc/godoc_test.go
generated
vendored
Normal file
477
vendor/golang.org/x/tools/cmd/godoc/godoc_test.go
generated
vendored
Normal file
@@ -0,0 +1,477 @@
|
||||
// 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 main_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// buildGodoc builds the godoc executable.
|
||||
// It returns its path, and a cleanup function.
|
||||
//
|
||||
// TODO(adonovan): opt: do this at most once, and do the cleanup
|
||||
// exactly once. How though? There's no atexit.
|
||||
func buildGodoc(t *testing.T) (bin string, cleanup func()) {
|
||||
if runtime.GOARCH == "arm" {
|
||||
t.Skip("skipping test on arm platforms; too slow")
|
||||
}
|
||||
tmp, err := ioutil.TempDir("", "godoc-regtest-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if cleanup == nil { // probably, go build failed.
|
||||
os.RemoveAll(tmp)
|
||||
}
|
||||
}()
|
||||
|
||||
bin = filepath.Join(tmp, "godoc")
|
||||
if runtime.GOOS == "windows" {
|
||||
bin += ".exe"
|
||||
}
|
||||
cmd := exec.Command("go", "build", "-o", bin)
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Fatalf("Building godoc: %v", err)
|
||||
}
|
||||
|
||||
return bin, func() { os.RemoveAll(tmp) }
|
||||
}
|
||||
|
||||
var isGo19 bool // godoc19_test.go sets it to true.
|
||||
|
||||
// Basic regression test for godoc command-line tool.
|
||||
func TestCLI(t *testing.T) {
|
||||
bin, cleanup := buildGodoc(t)
|
||||
defer cleanup()
|
||||
|
||||
// condStr returns s if cond is true, otherwise empty string.
|
||||
condStr := func(cond bool, s string) string {
|
||||
if !cond {
|
||||
return ""
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
args []string
|
||||
matches []string // regular expressions
|
||||
dontmatch []string // regular expressions
|
||||
}{
|
||||
{
|
||||
args: []string{"fmt"},
|
||||
matches: []string{
|
||||
`import "fmt"`,
|
||||
`Package fmt implements formatted I/O`,
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"io", "WriteString"},
|
||||
matches: []string{
|
||||
`func WriteString\(`,
|
||||
`WriteString writes the contents of the string s to w`,
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"nonexistingpkg"},
|
||||
matches: []string{
|
||||
`cannot find package` +
|
||||
// TODO: Remove this when support for Go 1.8 is dropped.
|
||||
condStr(!isGo19,
|
||||
// For Go 1.8 and older, because it doesn't have CL 33158 change applied to go/build.
|
||||
// The last pattern (does not e) is for plan9:
|
||||
// http://build.golang.org/log/2d8e5e14ed365bfa434b37ec0338cd9e6f8dd9bf
|
||||
`|no such file or directory|does not exist|cannot find the file|(?:' does not e)`),
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"fmt", "NonexistentSymbol"},
|
||||
matches: []string{
|
||||
`No match found\.`,
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"-src", "syscall", "Open"},
|
||||
matches: []string{
|
||||
`func Open\(`,
|
||||
},
|
||||
dontmatch: []string{
|
||||
`No match found\.`,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
cmd := exec.Command(bin, test.args...)
|
||||
cmd.Args[0] = "godoc"
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("Running with args %#v: %v", test.args, err)
|
||||
continue
|
||||
}
|
||||
for _, pat := range test.matches {
|
||||
re := regexp.MustCompile(pat)
|
||||
if !re.Match(out) {
|
||||
t.Errorf("godoc %v =\n%s\nwanted /%v/", strings.Join(test.args, " "), out, pat)
|
||||
}
|
||||
}
|
||||
for _, pat := range test.dontmatch {
|
||||
re := regexp.MustCompile(pat)
|
||||
if re.Match(out) {
|
||||
t.Errorf("godoc %v =\n%s\ndid not want /%v/", strings.Join(test.args, " "), out, pat)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func serverAddress(t *testing.T) string {
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
ln, err = net.Listen("tcp6", "[::1]:0")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
return ln.Addr().String()
|
||||
}
|
||||
|
||||
func waitForServerReady(t *testing.T, addr string) {
|
||||
waitForServer(t,
|
||||
fmt.Sprintf("http://%v/", addr),
|
||||
"The Go Programming Language",
|
||||
15*time.Second,
|
||||
false)
|
||||
}
|
||||
|
||||
func waitForSearchReady(t *testing.T, addr string) {
|
||||
waitForServer(t,
|
||||
fmt.Sprintf("http://%v/search?q=FALLTHROUGH", addr),
|
||||
"The list of tokens.",
|
||||
2*time.Minute,
|
||||
false)
|
||||
}
|
||||
|
||||
func waitUntilScanComplete(t *testing.T, addr string) {
|
||||
waitForServer(t,
|
||||
fmt.Sprintf("http://%v/pkg", addr),
|
||||
"Scan is not yet complete",
|
||||
2*time.Minute,
|
||||
true,
|
||||
)
|
||||
// setting reverse as true, which means this waits
|
||||
// until the string is not returned in the response anymore
|
||||
}
|
||||
|
||||
const pollInterval = 200 * time.Millisecond
|
||||
|
||||
func waitForServer(t *testing.T, url, match string, timeout time.Duration, reverse bool) {
|
||||
// "health check" duplicated from x/tools/cmd/tipgodoc/tip.go
|
||||
deadline := time.Now().Add(timeout)
|
||||
for time.Now().Before(deadline) {
|
||||
time.Sleep(pollInterval)
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
rbody, err := ioutil.ReadAll(res.Body)
|
||||
res.Body.Close()
|
||||
if err == nil && res.StatusCode == http.StatusOK {
|
||||
if bytes.Contains(rbody, []byte(match)) && !reverse {
|
||||
return
|
||||
}
|
||||
if !bytes.Contains(rbody, []byte(match)) && reverse {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Fatalf("Server failed to respond in %v", timeout)
|
||||
}
|
||||
|
||||
func killAndWait(cmd *exec.Cmd) {
|
||||
cmd.Process.Kill()
|
||||
cmd.Wait()
|
||||
}
|
||||
|
||||
// Basic integration test for godoc HTTP interface.
|
||||
func TestWeb(t *testing.T) {
|
||||
testWeb(t, false)
|
||||
}
|
||||
|
||||
// Basic integration test for godoc HTTP interface.
|
||||
func TestWebIndex(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in -short mode")
|
||||
}
|
||||
testWeb(t, true)
|
||||
}
|
||||
|
||||
// Basic integration test for godoc HTTP interface.
|
||||
func testWeb(t *testing.T, withIndex bool) {
|
||||
if runtime.GOOS == "plan9" {
|
||||
t.Skip("skipping on plan9; files to start up quickly enough")
|
||||
}
|
||||
bin, cleanup := buildGodoc(t)
|
||||
defer cleanup()
|
||||
addr := serverAddress(t)
|
||||
args := []string{fmt.Sprintf("-http=%s", addr)}
|
||||
if withIndex {
|
||||
args = append(args, "-index", "-index_interval=-1s")
|
||||
}
|
||||
cmd := exec.Command(bin, args...)
|
||||
cmd.Stdout = os.Stderr
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Args[0] = "godoc"
|
||||
|
||||
// Set GOPATH variable to non-existing path.
|
||||
// We cannot just unset GOPATH variable because godoc would default it to ~/go.
|
||||
// (We don't want the indexer looking at the local workspace during tests.)
|
||||
cmd.Env = append(os.Environ(), "GOPATH=does_not_exist")
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Fatalf("failed to start godoc: %s", err)
|
||||
}
|
||||
defer killAndWait(cmd)
|
||||
|
||||
if withIndex {
|
||||
waitForSearchReady(t, addr)
|
||||
} else {
|
||||
waitForServerReady(t, addr)
|
||||
waitUntilScanComplete(t, addr)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
path string
|
||||
match []string
|
||||
dontmatch []string
|
||||
needIndex bool
|
||||
}{
|
||||
{
|
||||
path: "/",
|
||||
match: []string{"Go is an open source programming language"},
|
||||
},
|
||||
{
|
||||
path: "/pkg/fmt/",
|
||||
match: []string{"Package fmt implements formatted I/O"},
|
||||
},
|
||||
{
|
||||
path: "/src/fmt/",
|
||||
match: []string{"scan_test.go"},
|
||||
},
|
||||
{
|
||||
path: "/src/fmt/print.go",
|
||||
match: []string{"// Println formats using"},
|
||||
},
|
||||
{
|
||||
path: "/pkg",
|
||||
match: []string{
|
||||
"Standard library",
|
||||
"Package fmt implements formatted I/O",
|
||||
},
|
||||
dontmatch: []string{
|
||||
"internal/syscall",
|
||||
"cmd/gc",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/pkg/?m=all",
|
||||
match: []string{
|
||||
"Standard library",
|
||||
"Package fmt implements formatted I/O",
|
||||
"internal/syscall/?m=all",
|
||||
},
|
||||
dontmatch: []string{
|
||||
"cmd/gc",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/search?q=ListenAndServe",
|
||||
match: []string{
|
||||
"/src",
|
||||
},
|
||||
dontmatch: []string{
|
||||
"/pkg/bootstrap",
|
||||
},
|
||||
needIndex: true,
|
||||
},
|
||||
{
|
||||
path: "/pkg/strings/",
|
||||
match: []string{
|
||||
`href="/src/strings/strings.go"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/cmd/compile/internal/amd64/",
|
||||
match: []string{
|
||||
`href="/src/cmd/compile/internal/amd64/ssa.go"`,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if test.needIndex && !withIndex {
|
||||
continue
|
||||
}
|
||||
url := fmt.Sprintf("http://%s%s", addr, test.path)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
t.Errorf("GET %s failed: %s", url, err)
|
||||
continue
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
t.Errorf("GET %s: failed to read body: %s (response: %v)", url, err, resp)
|
||||
}
|
||||
isErr := false
|
||||
for _, substr := range test.match {
|
||||
if !bytes.Contains(body, []byte(substr)) {
|
||||
t.Errorf("GET %s: wanted substring %q in body", url, substr)
|
||||
isErr = true
|
||||
}
|
||||
}
|
||||
for _, substr := range test.dontmatch {
|
||||
if bytes.Contains(body, []byte(substr)) {
|
||||
t.Errorf("GET %s: didn't want substring %q in body", url, substr)
|
||||
isErr = true
|
||||
}
|
||||
}
|
||||
if isErr {
|
||||
t.Errorf("GET %s: got:\n%s", url, body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Basic integration test for godoc -analysis=type (via HTTP interface).
|
||||
func TestTypeAnalysis(t *testing.T) {
|
||||
if runtime.GOOS == "plan9" {
|
||||
t.Skip("skipping test on plan9 (issue #11974)") // see comment re: Plan 9 below
|
||||
}
|
||||
|
||||
// Write a fake GOROOT/GOPATH.
|
||||
tmpdir, err := ioutil.TempDir("", "godoc-analysis")
|
||||
if err != nil {
|
||||
t.Fatalf("ioutil.TempDir failed: %s", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
for _, f := range []struct{ file, content string }{
|
||||
{"goroot/src/lib/lib.go", `
|
||||
package lib
|
||||
type T struct{}
|
||||
const C = 3
|
||||
var V T
|
||||
func (T) F() int { return C }
|
||||
`},
|
||||
{"gopath/src/app/main.go", `
|
||||
package main
|
||||
import "lib"
|
||||
func main() { print(lib.V) }
|
||||
`},
|
||||
} {
|
||||
file := filepath.Join(tmpdir, f.file)
|
||||
if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil {
|
||||
t.Fatalf("MkdirAll(%s) failed: %s", filepath.Dir(file), err)
|
||||
}
|
||||
if err := ioutil.WriteFile(file, []byte(f.content), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start the server.
|
||||
bin, cleanup := buildGodoc(t)
|
||||
defer cleanup()
|
||||
addr := serverAddress(t)
|
||||
cmd := exec.Command(bin, fmt.Sprintf("-http=%s", addr), "-analysis=type")
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("GOROOT=%s", filepath.Join(tmpdir, "goroot")))
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("GOPATH=%s", filepath.Join(tmpdir, "gopath")))
|
||||
cmd.Stdout = os.Stderr
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cmd.Args[0] = "godoc"
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Fatalf("failed to start godoc: %s", err)
|
||||
}
|
||||
defer killAndWait(cmd)
|
||||
waitForServerReady(t, addr)
|
||||
|
||||
// Wait for type analysis to complete.
|
||||
reader := bufio.NewReader(stderr)
|
||||
for {
|
||||
s, err := reader.ReadString('\n') // on Plan 9 this fails
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Fprint(os.Stderr, s)
|
||||
if strings.Contains(s, "Type analysis complete.") {
|
||||
break
|
||||
}
|
||||
}
|
||||
go io.Copy(os.Stderr, reader)
|
||||
|
||||
t0 := time.Now()
|
||||
|
||||
// Make an HTTP request and check for a regular expression match.
|
||||
// The patterns are very crude checks that basic type information
|
||||
// has been annotated onto the source view.
|
||||
tryagain:
|
||||
for _, test := range []struct{ url, pattern string }{
|
||||
{"/src/lib/lib.go", "L2.*package .*Package docs for lib.*/lib"},
|
||||
{"/src/lib/lib.go", "L3.*type .*type info for T.*struct"},
|
||||
{"/src/lib/lib.go", "L5.*var V .*type T struct"},
|
||||
{"/src/lib/lib.go", "L6.*func .*type T struct.*T.*return .*const C untyped int.*C"},
|
||||
|
||||
{"/src/app/main.go", "L2.*package .*Package docs for app"},
|
||||
{"/src/app/main.go", "L3.*import .*Package docs for lib.*lib"},
|
||||
{"/src/app/main.go", "L4.*func main.*package lib.*lib.*var lib.V lib.T.*V"},
|
||||
} {
|
||||
url := fmt.Sprintf("http://%s%s", addr, test.url)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
t.Errorf("GET %s failed: %s", url, err)
|
||||
continue
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
t.Errorf("GET %s: failed to read body: %s (response: %v)", url, err, resp)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Contains(body, []byte("Static analysis features")) {
|
||||
// Type analysis results usually become available within
|
||||
// ~4ms after godoc startup (for this input on my machine).
|
||||
if elapsed := time.Since(t0); elapsed > 500*time.Millisecond {
|
||||
t.Fatalf("type analysis results still unavailable after %s", elapsed)
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
goto tryagain
|
||||
}
|
||||
|
||||
match, err := regexp.Match(test.pattern, body)
|
||||
if err != nil {
|
||||
t.Errorf("regexp.Match(%q) failed: %s", test.pattern, err)
|
||||
continue
|
||||
}
|
||||
if !match {
|
||||
// This is a really ugly failure message.
|
||||
t.Errorf("GET %s: body doesn't match %q, got:\n%s",
|
||||
url, test.pattern, string(body))
|
||||
}
|
||||
}
|
||||
}
|
74
vendor/golang.org/x/tools/cmd/godoc/goroot.go
generated
vendored
Normal file
74
vendor/golang.org/x/tools/cmd/godoc/goroot.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Copies of functions from src/cmd/go/internal/cfg/cfg.go for
|
||||
// finding the GOROOT.
|
||||
// Keep them in sync until support is moved to a common place, if ever.
|
||||
|
||||
func findGOROOT() string {
|
||||
if env := os.Getenv("GOROOT"); env != "" {
|
||||
return filepath.Clean(env)
|
||||
}
|
||||
def := filepath.Clean(runtime.GOROOT())
|
||||
if runtime.Compiler == "gccgo" {
|
||||
// gccgo has no real GOROOT, and it certainly doesn't
|
||||
// depend on the executable's location.
|
||||
return def
|
||||
}
|
||||
exe, err := os.Executable()
|
||||
if err == nil {
|
||||
exe, err = filepath.Abs(exe)
|
||||
if err == nil {
|
||||
if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
|
||||
// If def (runtime.GOROOT()) and dir are the same
|
||||
// directory, prefer the spelling used in def.
|
||||
if isSameDir(def, dir) {
|
||||
return def
|
||||
}
|
||||
return dir
|
||||
}
|
||||
exe, err = filepath.EvalSymlinks(exe)
|
||||
if err == nil {
|
||||
if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
|
||||
if isSameDir(def, dir) {
|
||||
return def
|
||||
}
|
||||
return dir
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// isGOROOT reports whether path looks like a GOROOT.
|
||||
//
|
||||
// It does this by looking for the path/pkg/tool directory,
|
||||
// which is necessary for useful operation of the cmd/go tool,
|
||||
// and is not typically present in a GOPATH.
|
||||
func isGOROOT(path string) bool {
|
||||
stat, err := os.Stat(filepath.Join(path, "pkg", "tool"))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return stat.IsDir()
|
||||
}
|
||||
|
||||
// isSameDir reports whether dir1 and dir2 are the same directory.
|
||||
func isSameDir(dir1, dir2 string) bool {
|
||||
if dir1 == dir2 {
|
||||
return true
|
||||
}
|
||||
info1, err1 := os.Stat(dir1)
|
||||
info2, err2 := os.Stat(dir2)
|
||||
return err1 == nil && err2 == nil && os.SameFile(info1, info2)
|
||||
}
|
149
vendor/golang.org/x/tools/cmd/godoc/handlers.go
generated
vendored
Normal file
149
vendor/golang.org/x/tools/cmd/godoc/handlers.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
// The /doc/codewalk/ tree is synthesized from codewalk descriptions,
|
||||
// files named $GOROOT/doc/codewalk/*.xml.
|
||||
// For an example and a description of the format, see
|
||||
// http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060
|
||||
// and see http://localhost:6060/doc/codewalk/codewalk .
|
||||
// That page is itself a codewalk; the source code for it is
|
||||
// $GOROOT/doc/codewalk/codewalk.xml.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"go/format"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"golang.org/x/tools/godoc"
|
||||
"golang.org/x/tools/godoc/redirect"
|
||||
"golang.org/x/tools/godoc/vfs"
|
||||
)
|
||||
|
||||
var (
|
||||
pres *godoc.Presentation
|
||||
fs = vfs.NameSpace{}
|
||||
)
|
||||
|
||||
var enforceHosts = false // set true in production on app engine
|
||||
|
||||
// hostEnforcerHandler redirects requests to "http://foo.golang.org/bar"
|
||||
// to "https://golang.org/bar".
|
||||
// It permits requests to the host "godoc-test.golang.org" for testing and
|
||||
// golang.google.cn for Chinese users.
|
||||
type hostEnforcerHandler struct {
|
||||
h http.Handler
|
||||
}
|
||||
|
||||
func (h hostEnforcerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if !enforceHosts {
|
||||
h.h.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
if r.TLS == nil || !h.validHost(r.Host) {
|
||||
r.URL.Scheme = "https"
|
||||
if h.validHost(r.Host) {
|
||||
r.URL.Host = r.Host
|
||||
} else {
|
||||
r.URL.Host = "golang.org"
|
||||
}
|
||||
http.Redirect(w, r, r.URL.String(), http.StatusFound)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
|
||||
h.h.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (h hostEnforcerHandler) validHost(host string) bool {
|
||||
switch strings.ToLower(host) {
|
||||
case "golang.org", "godoc-test.golang.org", "golang.google.cn":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func registerHandlers(pres *godoc.Presentation) *http.ServeMux {
|
||||
if pres == nil {
|
||||
panic("nil Presentation")
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/doc/codewalk/", codewalk)
|
||||
mux.Handle("/doc/play/", pres.FileServer())
|
||||
mux.Handle("/robots.txt", pres.FileServer())
|
||||
mux.Handle("/", pres)
|
||||
mux.Handle("/pkg/C/", redirect.Handler("/cmd/cgo/"))
|
||||
mux.HandleFunc("/fmt", fmtHandler)
|
||||
redirect.Register(mux)
|
||||
|
||||
http.Handle("/", hostEnforcerHandler{mux})
|
||||
|
||||
return mux
|
||||
}
|
||||
|
||||
func readTemplate(name string) *template.Template {
|
||||
if pres == nil {
|
||||
panic("no global Presentation set yet")
|
||||
}
|
||||
path := "lib/godoc/" + name
|
||||
|
||||
// use underlying file system fs to read the template file
|
||||
// (cannot use template ParseFile functions directly)
|
||||
data, err := vfs.ReadFile(fs, path)
|
||||
if err != nil {
|
||||
log.Fatal("readTemplate: ", err)
|
||||
}
|
||||
// be explicit with errors (for app engine use)
|
||||
t, err := template.New(name).Funcs(pres.FuncMap()).Parse(string(data))
|
||||
if err != nil {
|
||||
log.Fatal("readTemplate: ", err)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func readTemplates(p *godoc.Presentation, html bool) {
|
||||
p.PackageText = readTemplate("package.txt")
|
||||
p.SearchText = readTemplate("search.txt")
|
||||
|
||||
if html || p.HTMLMode {
|
||||
codewalkHTML = readTemplate("codewalk.html")
|
||||
codewalkdirHTML = readTemplate("codewalkdir.html")
|
||||
p.CallGraphHTML = readTemplate("callgraph.html")
|
||||
p.DirlistHTML = readTemplate("dirlist.html")
|
||||
p.ErrorHTML = readTemplate("error.html")
|
||||
p.ExampleHTML = readTemplate("example.html")
|
||||
p.GodocHTML = readTemplate("godoc.html")
|
||||
p.ImplementsHTML = readTemplate("implements.html")
|
||||
p.MethodSetHTML = readTemplate("methodset.html")
|
||||
p.PackageHTML = readTemplate("package.html")
|
||||
p.PackageRootHTML = readTemplate("packageroot.html")
|
||||
p.SearchHTML = readTemplate("search.html")
|
||||
p.SearchDocHTML = readTemplate("searchdoc.html")
|
||||
p.SearchCodeHTML = readTemplate("searchcode.html")
|
||||
p.SearchTxtHTML = readTemplate("searchtxt.html")
|
||||
p.SearchDescXML = readTemplate("opensearch.xml")
|
||||
}
|
||||
}
|
||||
|
||||
type fmtResponse struct {
|
||||
Body string
|
||||
Error string
|
||||
}
|
||||
|
||||
// fmtHandler takes a Go program in its "body" form value, formats it with
|
||||
// standard gofmt formatting, and writes a fmtResponse as a JSON object.
|
||||
func fmtHandler(w http.ResponseWriter, r *http.Request) {
|
||||
resp := new(fmtResponse)
|
||||
body, err := format.Source([]byte(r.FormValue("body")))
|
||||
if err != nil {
|
||||
resp.Error = err.Error()
|
||||
} else {
|
||||
resp.Body = string(body)
|
||||
}
|
||||
w.Header().Set("Content-type", "application/json; charset=utf-8")
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
11
vendor/golang.org/x/tools/cmd/godoc/index.go
generated
vendored
Normal file
11
vendor/golang.org/x/tools/cmd/godoc/index.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import "strings"
|
||||
|
||||
func indexDirectoryDefault(dir string) bool {
|
||||
return dir != "/pkg" && !strings.HasPrefix(dir, "/pkg/")
|
||||
}
|
371
vendor/golang.org/x/tools/cmd/godoc/main.go
generated
vendored
Normal file
371
vendor/golang.org/x/tools/cmd/godoc/main.go
generated
vendored
Normal file
@@ -0,0 +1,371 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
// godoc: Go Documentation Server
|
||||
|
||||
// Web server tree:
|
||||
//
|
||||
// http://godoc/ main landing page
|
||||
// http://godoc/doc/ serve from $GOROOT/doc - spec, mem, etc.
|
||||
// http://godoc/src/ serve files from $GOROOT/src; .go gets pretty-printed
|
||||
// http://godoc/cmd/ serve documentation about commands
|
||||
// http://godoc/pkg/ serve documentation about packages
|
||||
// (idea is if you say import "compress/zlib", you go to
|
||||
// http://godoc/pkg/compress/zlib)
|
||||
//
|
||||
// Command-line interface:
|
||||
//
|
||||
// godoc packagepath [name ...]
|
||||
//
|
||||
// godoc compress/zlib
|
||||
// - prints doc for package compress/zlib
|
||||
// godoc crypto/block Cipher NewCMAC
|
||||
// - prints doc for Cipher and NewCMAC in package crypto/block
|
||||
|
||||
// +build !appengine
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
_ "expvar" // to serve /debug/vars
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
_ "net/http/pprof" // to serve /debug/pprof/*
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/godoc"
|
||||
"golang.org/x/tools/godoc/analysis"
|
||||
"golang.org/x/tools/godoc/static"
|
||||
"golang.org/x/tools/godoc/vfs"
|
||||
"golang.org/x/tools/godoc/vfs/gatefs"
|
||||
"golang.org/x/tools/godoc/vfs/mapfs"
|
||||
"golang.org/x/tools/godoc/vfs/zipfs"
|
||||
)
|
||||
|
||||
const defaultAddr = ":6060" // default webserver address
|
||||
|
||||
var (
|
||||
// file system to serve
|
||||
// (with e.g.: zip -r go.zip $GOROOT -i \*.go -i \*.html -i \*.css -i \*.js -i \*.txt -i \*.c -i \*.h -i \*.s -i \*.png -i \*.jpg -i \*.sh -i favicon.ico)
|
||||
zipfile = flag.String("zip", "", "zip file providing the file system to serve; disabled if empty")
|
||||
|
||||
// file-based index
|
||||
writeIndex = flag.Bool("write_index", false, "write index to a file; the file name must be specified with -index_files")
|
||||
|
||||
analysisFlag = flag.String("analysis", "", `comma-separated list of analyses to perform (supported: type, pointer). See http://golang.org/lib/godoc/analysis/help.html`)
|
||||
|
||||
// network
|
||||
httpAddr = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')")
|
||||
serverAddr = flag.String("server", "", "webserver address for command line searches")
|
||||
|
||||
// layout control
|
||||
html = flag.Bool("html", false, "print HTML in command-line mode")
|
||||
srcMode = flag.Bool("src", false, "print (exported) source in command-line mode")
|
||||
allMode = flag.Bool("all", false, "include unexported identifiers in command-line mode")
|
||||
urlFlag = flag.String("url", "", "print HTML for named URL")
|
||||
|
||||
// command-line searches
|
||||
query = flag.Bool("q", false, "arguments are considered search queries")
|
||||
|
||||
verbose = flag.Bool("v", false, "verbose mode")
|
||||
|
||||
// file system roots
|
||||
// TODO(gri) consider the invariant that goroot always end in '/'
|
||||
goroot = flag.String("goroot", findGOROOT(), "Go root directory")
|
||||
|
||||
// layout control
|
||||
tabWidth = flag.Int("tabwidth", 4, "tab width")
|
||||
showTimestamps = flag.Bool("timestamps", false, "show timestamps with directory listings")
|
||||
templateDir = flag.String("templates", "", "load templates/JS/CSS from disk in this directory")
|
||||
showPlayground = flag.Bool("play", false, "enable playground in web interface")
|
||||
showExamples = flag.Bool("ex", false, "show examples in command line mode")
|
||||
declLinks = flag.Bool("links", true, "link identifiers to their declarations")
|
||||
|
||||
// search index
|
||||
indexEnabled = flag.Bool("index", false, "enable search index")
|
||||
indexFiles = flag.String("index_files", "", "glob pattern specifying index files; if not empty, the index is read from these files in sorted order")
|
||||
indexInterval = flag.Duration("index_interval", 0, "interval of indexing; 0 for default (5m), negative to only index once at startup")
|
||||
maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
|
||||
indexThrottle = flag.Float64("index_throttle", 0.75, "index throttle value; 0.0 = no time allocated, 1.0 = full throttle")
|
||||
|
||||
// source code notes
|
||||
notesRx = flag.String("notes", "BUG", "regular expression matching note markers to show")
|
||||
)
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr,
|
||||
"usage: godoc package [name ...]\n"+
|
||||
" godoc -http="+defaultAddr+"\n")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
func loggingHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
log.Printf("%s\t%s", req.RemoteAddr, req.URL)
|
||||
h.ServeHTTP(w, req)
|
||||
})
|
||||
}
|
||||
|
||||
func handleURLFlag() {
|
||||
// Try up to 10 fetches, following redirects.
|
||||
urlstr := *urlFlag
|
||||
for i := 0; i < 10; i++ {
|
||||
// Prepare request.
|
||||
u, err := url.Parse(urlstr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
req := &http.Request{
|
||||
URL: u,
|
||||
}
|
||||
|
||||
// Invoke default HTTP handler to serve request
|
||||
// to our buffering httpWriter.
|
||||
w := httptest.NewRecorder()
|
||||
http.DefaultServeMux.ServeHTTP(w, req)
|
||||
|
||||
// Return data, error, or follow redirect.
|
||||
switch w.Code {
|
||||
case 200: // ok
|
||||
os.Stdout.Write(w.Body.Bytes())
|
||||
return
|
||||
case 301, 302, 303, 307: // redirect
|
||||
redirect := w.HeaderMap.Get("Location")
|
||||
if redirect == "" {
|
||||
log.Fatalf("HTTP %d without Location header", w.Code)
|
||||
}
|
||||
urlstr = redirect
|
||||
default:
|
||||
log.Fatalf("HTTP error %d", w.Code)
|
||||
}
|
||||
}
|
||||
log.Fatalf("too many redirects")
|
||||
}
|
||||
|
||||
func initCorpus(corpus *godoc.Corpus) {
|
||||
err := corpus.Init()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
|
||||
if certInit != nil {
|
||||
certInit()
|
||||
}
|
||||
|
||||
playEnabled = *showPlayground
|
||||
|
||||
// Check usage: server and no args.
|
||||
if (*httpAddr != "" || *urlFlag != "") && (flag.NArg() > 0) {
|
||||
fmt.Fprintln(os.Stderr, "can't use -http with args.")
|
||||
usage()
|
||||
}
|
||||
|
||||
// Check usage: command line args or index creation mode.
|
||||
if (*httpAddr != "" || *urlFlag != "") != (flag.NArg() == 0) && !*writeIndex {
|
||||
fmt.Fprintln(os.Stderr, "missing args.")
|
||||
usage()
|
||||
}
|
||||
|
||||
var fsGate chan bool
|
||||
fsGate = make(chan bool, 20)
|
||||
|
||||
// Determine file system to use.
|
||||
if *zipfile == "" {
|
||||
// use file system of underlying OS
|
||||
rootfs := gatefs.New(vfs.OS(*goroot), fsGate)
|
||||
fs.Bind("/", rootfs, "/", vfs.BindReplace)
|
||||
} else {
|
||||
// use file system specified via .zip file (path separator must be '/')
|
||||
rc, err := zip.OpenReader(*zipfile)
|
||||
if err != nil {
|
||||
log.Fatalf("%s: %s\n", *zipfile, err)
|
||||
}
|
||||
defer rc.Close() // be nice (e.g., -writeIndex mode)
|
||||
fs.Bind("/", zipfs.New(rc, *zipfile), *goroot, vfs.BindReplace)
|
||||
}
|
||||
if *templateDir != "" {
|
||||
fs.Bind("/lib/godoc", vfs.OS(*templateDir), "/", vfs.BindBefore)
|
||||
} else {
|
||||
fs.Bind("/lib/godoc", mapfs.New(static.Files), "/", vfs.BindReplace)
|
||||
}
|
||||
|
||||
// Bind $GOPATH trees into Go root.
|
||||
for _, p := range filepath.SplitList(build.Default.GOPATH) {
|
||||
fs.Bind("/src", gatefs.New(vfs.OS(p), fsGate), "/src", vfs.BindAfter)
|
||||
}
|
||||
|
||||
httpMode := *httpAddr != ""
|
||||
|
||||
var typeAnalysis, pointerAnalysis bool
|
||||
if *analysisFlag != "" {
|
||||
for _, a := range strings.Split(*analysisFlag, ",") {
|
||||
switch a {
|
||||
case "type":
|
||||
typeAnalysis = true
|
||||
case "pointer":
|
||||
pointerAnalysis = true
|
||||
default:
|
||||
log.Fatalf("unknown analysis: %s", a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
corpus := godoc.NewCorpus(fs)
|
||||
corpus.Verbose = *verbose
|
||||
corpus.MaxResults = *maxResults
|
||||
corpus.IndexEnabled = *indexEnabled && httpMode
|
||||
if *maxResults == 0 {
|
||||
corpus.IndexFullText = false
|
||||
}
|
||||
corpus.IndexFiles = *indexFiles
|
||||
corpus.IndexDirectory = indexDirectoryDefault
|
||||
corpus.IndexThrottle = *indexThrottle
|
||||
corpus.IndexInterval = *indexInterval
|
||||
if *writeIndex {
|
||||
corpus.IndexThrottle = 1.0
|
||||
corpus.IndexEnabled = true
|
||||
}
|
||||
if *writeIndex || httpMode || *urlFlag != "" {
|
||||
if httpMode {
|
||||
go initCorpus(corpus)
|
||||
} else {
|
||||
initCorpus(corpus)
|
||||
}
|
||||
}
|
||||
|
||||
pres = godoc.NewPresentation(corpus)
|
||||
pres.TabWidth = *tabWidth
|
||||
pres.ShowTimestamps = *showTimestamps
|
||||
pres.ShowPlayground = *showPlayground
|
||||
pres.ShowExamples = *showExamples
|
||||
pres.DeclLinks = *declLinks
|
||||
pres.SrcMode = *srcMode
|
||||
pres.HTMLMode = *html
|
||||
pres.AllMode = *allMode
|
||||
if *notesRx != "" {
|
||||
pres.NotesRx = regexp.MustCompile(*notesRx)
|
||||
}
|
||||
|
||||
readTemplates(pres, httpMode || *urlFlag != "")
|
||||
registerHandlers(pres)
|
||||
|
||||
if *writeIndex {
|
||||
// Write search index and exit.
|
||||
if *indexFiles == "" {
|
||||
log.Fatal("no index file specified")
|
||||
}
|
||||
|
||||
log.Println("initialize file systems")
|
||||
*verbose = true // want to see what happens
|
||||
|
||||
corpus.UpdateIndex()
|
||||
|
||||
log.Println("writing index file", *indexFiles)
|
||||
f, err := os.Create(*indexFiles)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
index, _ := corpus.CurrentIndex()
|
||||
_, err = index.WriteTo(f)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Println("done")
|
||||
return
|
||||
}
|
||||
|
||||
// Print content that would be served at the URL *urlFlag.
|
||||
if *urlFlag != "" {
|
||||
handleURLFlag()
|
||||
return
|
||||
}
|
||||
|
||||
if httpMode {
|
||||
// HTTP server mode.
|
||||
var handler http.Handler = http.DefaultServeMux
|
||||
if *verbose {
|
||||
log.Printf("Go Documentation Server")
|
||||
log.Printf("version = %s", runtime.Version())
|
||||
log.Printf("address = %s", *httpAddr)
|
||||
log.Printf("goroot = %s", *goroot)
|
||||
log.Printf("tabwidth = %d", *tabWidth)
|
||||
switch {
|
||||
case !*indexEnabled:
|
||||
log.Print("search index disabled")
|
||||
case *maxResults > 0:
|
||||
log.Printf("full text index enabled (maxresults = %d)", *maxResults)
|
||||
default:
|
||||
log.Print("identifier search index enabled")
|
||||
}
|
||||
fs.Fprint(os.Stderr)
|
||||
handler = loggingHandler(handler)
|
||||
}
|
||||
|
||||
// Initialize search index.
|
||||
if *indexEnabled {
|
||||
go corpus.RunIndexer()
|
||||
}
|
||||
|
||||
// Start type/pointer analysis.
|
||||
if typeAnalysis || pointerAnalysis {
|
||||
go analysis.Run(pointerAnalysis, &corpus.Analysis)
|
||||
}
|
||||
|
||||
if runHTTPS != nil {
|
||||
go func() {
|
||||
if err := runHTTPS(handler); err != nil {
|
||||
log.Fatalf("ListenAndServe TLS: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Start http server.
|
||||
if *verbose {
|
||||
log.Println("starting HTTP server")
|
||||
}
|
||||
if wrapHTTPMux != nil {
|
||||
handler = wrapHTTPMux(handler)
|
||||
}
|
||||
if err := http.ListenAndServe(*httpAddr, handler); err != nil {
|
||||
log.Fatalf("ListenAndServe %s: %v", *httpAddr, err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if *query {
|
||||
handleRemoteSearch()
|
||||
return
|
||||
}
|
||||
|
||||
build.Default.GOROOT = *goroot
|
||||
if err := godoc.CommandLine(os.Stdout, fs, pres, flag.Args()); err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Hooks that are set non-nil in autocert.go if the "autocert" build tag
|
||||
// is used.
|
||||
var (
|
||||
certInit func()
|
||||
runHTTPS func(http.Handler) error
|
||||
wrapHTTPMux func(http.Handler) http.Handler
|
||||
)
|
11
vendor/golang.org/x/tools/cmd/godoc/play.go
generated
vendored
Normal file
11
vendor/golang.org/x/tools/cmd/godoc/play.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2012 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 main
|
||||
|
||||
// This package registers "/compile" and "/share" handlers
|
||||
// that redirect to the golang.org playground.
|
||||
import _ "golang.org/x/tools/playground"
|
72
vendor/golang.org/x/tools/cmd/godoc/remotesearch.go
generated
vendored
Normal file
72
vendor/golang.org/x/tools/cmd/godoc/remotesearch.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2009 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 main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
)
|
||||
|
||||
func handleRemoteSearch() {
|
||||
// Command-line queries.
|
||||
for i := 0; i < flag.NArg(); i++ {
|
||||
res, err := remoteSearch(flag.Arg(i))
|
||||
if err != nil {
|
||||
log.Fatalf("remoteSearch: %s", err)
|
||||
}
|
||||
io.Copy(os.Stdout, res.Body)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// remoteSearchURL returns the search URL for a given query as needed by
|
||||
// remoteSearch. If html is set, an html result is requested; otherwise
|
||||
// the result is in textual form.
|
||||
// Adjust this function as necessary if modeNames or FormValue parameters
|
||||
// change.
|
||||
func remoteSearchURL(query string, html bool) string {
|
||||
s := "/search?m=text&q="
|
||||
if html {
|
||||
s = "/search?q="
|
||||
}
|
||||
return s + url.QueryEscape(query)
|
||||
}
|
||||
|
||||
func remoteSearch(query string) (res *http.Response, err error) {
|
||||
// list of addresses to try
|
||||
var addrs []string
|
||||
if *serverAddr != "" {
|
||||
// explicit server address - only try this one
|
||||
addrs = []string{*serverAddr}
|
||||
} else {
|
||||
addrs = []string{
|
||||
defaultAddr,
|
||||
"golang.org",
|
||||
}
|
||||
}
|
||||
|
||||
// remote search
|
||||
search := remoteSearchURL(query, *html)
|
||||
for _, addr := range addrs {
|
||||
url := "http://" + addr + search
|
||||
res, err = http.Get(url)
|
||||
if err == nil && res.StatusCode == http.StatusOK {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && res.StatusCode != http.StatusOK {
|
||||
err = errors.New(res.Status)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
134
vendor/golang.org/x/tools/cmd/godoc/setup-godoc-app.bash
generated
vendored
Executable file
134
vendor/golang.org/x/tools/cmd/godoc/setup-godoc-app.bash
generated
vendored
Executable file
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2011 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 script creates a complete godoc app in $APPDIR.
|
||||
# It copies the cmd/godoc and src/go/... sources from GOROOT,
|
||||
# synthesizes an app.yaml file, and creates the .zip, index, and
|
||||
# configuration files.
|
||||
#
|
||||
# If an argument is provided it is assumed to be the app-engine godoc directory.
|
||||
# Without an argument, $APPDIR is used instead. If GOROOT is not set, "go env"
|
||||
# is consulted to find the $GOROOT.
|
||||
#
|
||||
# The script creates a .zip file representing the $GOROOT file system
|
||||
# and computes the correspondig search index files. These files are then
|
||||
# copied to $APPDIR. A corresponding godoc configuration file is created
|
||||
# in $APPDIR/appconfig.go.
|
||||
|
||||
ZIPFILE=godoc.zip
|
||||
INDEXFILE=godoc.index
|
||||
SPLITFILES=index.split.
|
||||
GODOC=golang.org/x/tools/cmd/godoc
|
||||
CONFIGFILE=$GODOC/appconfig.go
|
||||
|
||||
error() {
|
||||
echo "error: $1"
|
||||
exit 2
|
||||
}
|
||||
|
||||
getArgs() {
|
||||
if [ -z $APPENGINE_SDK ]; then
|
||||
error "APPENGINE_SDK environment variable not set"
|
||||
fi
|
||||
if [ ! -x $APPENGINE_SDK/goapp ]; then
|
||||
error "couldn't find goapp command in $APPENGINE_SDK"
|
||||
fi
|
||||
if [ -z $GOROOT ]; then
|
||||
GOROOT=$(go env GOROOT)
|
||||
echo "GOROOT not set explicitly, using go env value instead"
|
||||
fi
|
||||
if [ -z $APPDIR ]; then
|
||||
if [ $# == 0 ]; then
|
||||
error "APPDIR not set, and no argument provided"
|
||||
fi
|
||||
APPDIR=$1
|
||||
echo "APPDIR not set, using argument instead"
|
||||
fi
|
||||
|
||||
# safety checks
|
||||
if [ ! -d $GOROOT ]; then
|
||||
error "$GOROOT is not a directory"
|
||||
fi
|
||||
if [ -e $APPDIR ]; then
|
||||
error "$APPDIR exists; check and remove it before trying again"
|
||||
fi
|
||||
|
||||
# reporting
|
||||
echo "GOROOT = $GOROOT"
|
||||
echo "APPDIR = $APPDIR"
|
||||
}
|
||||
|
||||
fetchGodoc() {
|
||||
echo "*** Fetching godoc (if not already in GOPATH)"
|
||||
unset GOBIN
|
||||
go=$APPENGINE_SDK/goapp
|
||||
$go get -d -tags appengine $GODOC
|
||||
mkdir -p $APPDIR/$GODOC
|
||||
cp $(find $($go list -f '{{.Dir}}' $GODOC) -mindepth 1 -maxdepth 1 -type f) $APPDIR/$GODOC/
|
||||
}
|
||||
|
||||
makeAppYaml() {
|
||||
echo "*** make $APPDIR/app.yaml"
|
||||
cat > $APPDIR/app.yaml <<EOF
|
||||
application: godoc
|
||||
version: 1
|
||||
runtime: go
|
||||
api_version: go1
|
||||
|
||||
handlers:
|
||||
- url: /.*
|
||||
script: _go_app
|
||||
EOF
|
||||
}
|
||||
|
||||
makeZipfile() {
|
||||
echo "*** make $APPDIR/$ZIPFILE"
|
||||
zip -q -r $APPDIR/$ZIPFILE $GOROOT/*
|
||||
}
|
||||
|
||||
makeIndexfile() {
|
||||
echo "*** make $APPDIR/$INDEXFILE"
|
||||
GOPATH= godoc -write_index -index_files=$APPDIR/$INDEXFILE -zip=$APPDIR/$ZIPFILE
|
||||
}
|
||||
|
||||
splitIndexfile() {
|
||||
echo "*** split $APPDIR/$INDEXFILE"
|
||||
split -b8m $APPDIR/$INDEXFILE $APPDIR/$SPLITFILES
|
||||
}
|
||||
|
||||
makeConfigfile() {
|
||||
echo "*** make $APPDIR/$CONFIGFILE"
|
||||
cat > $APPDIR/$CONFIGFILE <<EOF
|
||||
package main
|
||||
|
||||
// GENERATED FILE - DO NOT MODIFY BY HAND.
|
||||
// (generated by golang.org/x/tools/cmd/godoc/setup-godoc-app.bash)
|
||||
|
||||
const (
|
||||
// .zip filename
|
||||
zipFilename = "$ZIPFILE"
|
||||
|
||||
// goroot directory in .zip file
|
||||
zipGoroot = "$GOROOT"
|
||||
|
||||
// glob pattern describing search index files
|
||||
// (if empty, the index is built at run-time)
|
||||
indexFilenames = "$SPLITFILES*"
|
||||
)
|
||||
EOF
|
||||
}
|
||||
|
||||
getArgs "$@"
|
||||
set -e
|
||||
mkdir $APPDIR
|
||||
fetchGodoc
|
||||
makeAppYaml
|
||||
makeZipfile
|
||||
makeIndexfile
|
||||
splitIndexfile
|
||||
makeConfigfile
|
||||
|
||||
echo "*** setup complete"
|
92
vendor/golang.org/x/tools/cmd/godoc/x.go
generated
vendored
Normal file
92
vendor/golang.org/x/tools/cmd/godoc/x.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
// 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.
|
||||
|
||||
// This file contains the handlers that serve go-import redirects for Go
|
||||
// sub-repositories. It specifies the mapping from import paths like
|
||||
// "golang.org/x/tools" to the actual repository locations.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const xPrefix = "/x/"
|
||||
|
||||
type xRepo struct {
|
||||
URL, VCS string
|
||||
}
|
||||
|
||||
var xMap = map[string]xRepo{
|
||||
"codereview": {"https://code.google.com/p/go.codereview", "hg"}, // Not included at https://golang.org/pkg/#subrepo.
|
||||
|
||||
"arch": {"https://go.googlesource.com/arch", "git"}, // Not included at https://golang.org/pkg/#subrepo.
|
||||
"benchmarks": {"https://go.googlesource.com/benchmarks", "git"},
|
||||
"blog": {"https://go.googlesource.com/blog", "git"},
|
||||
"build": {"https://go.googlesource.com/build", "git"},
|
||||
"crypto": {"https://go.googlesource.com/crypto", "git"},
|
||||
"debug": {"https://go.googlesource.com/debug", "git"},
|
||||
"exp": {"https://go.googlesource.com/exp", "git"},
|
||||
"image": {"https://go.googlesource.com/image", "git"},
|
||||
"lint": {"https://go.googlesource.com/lint", "git"}, // Not included at https://golang.org/pkg/#subrepo.
|
||||
"mobile": {"https://go.googlesource.com/mobile", "git"},
|
||||
"net": {"https://go.googlesource.com/net", "git"},
|
||||
"oauth2": {"https://go.googlesource.com/oauth2", "git"}, // Not included at https://golang.org/pkg/#subrepo.
|
||||
"perf": {"https://go.googlesource.com/perf", "git"},
|
||||
"playground": {"https://go.googlesource.com/playground", "git"}, // Not included at https://golang.org/pkg/#subrepo.
|
||||
"review": {"https://go.googlesource.com/review", "git"},
|
||||
"sync": {"https://go.googlesource.com/sync", "git"},
|
||||
"sys": {"https://go.googlesource.com/sys", "git"},
|
||||
"talks": {"https://go.googlesource.com/talks", "git"}, // Not included at https://golang.org/pkg/#subrepo.
|
||||
"term": {"https://go.googlesource.com/term", "git"}, // Not included at https://golang.org/pkg/#subrepo.
|
||||
"text": {"https://go.googlesource.com/text", "git"},
|
||||
"time": {"https://go.googlesource.com/time", "git"},
|
||||
"tools": {"https://go.googlesource.com/tools", "git"},
|
||||
"tour": {"https://go.googlesource.com/tour", "git"},
|
||||
"vgo": {"https://go.googlesource.com/vgo", "git"}, // Not included at https://golang.org/pkg/#subrepo.
|
||||
}
|
||||
|
||||
func init() {
|
||||
http.HandleFunc(xPrefix, xHandler)
|
||||
}
|
||||
|
||||
func xHandler(w http.ResponseWriter, r *http.Request) {
|
||||
head, tail := strings.TrimPrefix(r.URL.Path, xPrefix), ""
|
||||
if i := strings.Index(head, "/"); i != -1 {
|
||||
head, tail = head[:i], head[i:]
|
||||
}
|
||||
if head == "" {
|
||||
http.Redirect(w, r, "https://godoc.org/-/subrepo", http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
repo, ok := xMap[head]
|
||||
if !ok {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
data := struct {
|
||||
Prefix, Head, Tail string
|
||||
Repo xRepo
|
||||
}{xPrefix, head, tail, repo}
|
||||
if err := xTemplate.Execute(w, data); err != nil {
|
||||
log.Println("xHandler:", err)
|
||||
}
|
||||
}
|
||||
|
||||
var xTemplate = template.Must(template.New("x").Parse(`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta name="go-import" content="golang.org{{.Prefix}}{{.Head}} {{.Repo.VCS}} {{.Repo.URL}}">
|
||||
<meta name="go-source" content="golang.org{{.Prefix}}{{.Head}} https://github.com/golang/{{.Head}}/ https://github.com/golang/{{.Head}}/tree/master{/dir} https://github.com/golang/{{.Head}}/blob/master{/dir}/{file}#L{line}">
|
||||
<meta http-equiv="refresh" content="0; url=https://godoc.org/golang.org{{.Prefix}}{{.Head}}{{.Tail}}">
|
||||
</head>
|
||||
<body>
|
||||
Nothing to see here; <a href="https://godoc.org/golang.org{{.Prefix}}{{.Head}}{{.Tail}}">move along</a>.
|
||||
</body>
|
||||
</html>
|
||||
`))
|
Reference in New Issue
Block a user