Major rewrite
* use dep for vendoring * lets encrypt * moved web to transfer.sh-web repo * single command install * added first tests
This commit is contained in:
656
vendor/github.com/golang/gddo/doc/builder.go
generated
vendored
Normal file
656
vendor/github.com/golang/gddo/doc/builder.go
generated
vendored
Normal file
@@ -0,0 +1,656 @@
|
||||
// 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
package doc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/doc"
|
||||
"go/format"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/golang/gddo/gosrc"
|
||||
)
|
||||
|
||||
func startsWithUppercase(s string) bool {
|
||||
r, _ := utf8.DecodeRuneInString(s)
|
||||
return unicode.IsUpper(r)
|
||||
}
|
||||
|
||||
var badSynopsisPrefixes = []string{
|
||||
"Autogenerated by Thrift Compiler",
|
||||
"Automatically generated ",
|
||||
"Auto-generated by ",
|
||||
"Copyright ",
|
||||
"COPYRIGHT ",
|
||||
`THE SOFTWARE IS PROVIDED "AS IS"`,
|
||||
"TODO: ",
|
||||
"vim:",
|
||||
}
|
||||
|
||||
// synopsis extracts the first sentence from s. All runs of whitespace are
|
||||
// replaced by a single space.
|
||||
func synopsis(s string) string {
|
||||
|
||||
parts := strings.SplitN(s, "\n\n", 2)
|
||||
s = parts[0]
|
||||
|
||||
var buf []byte
|
||||
const (
|
||||
other = iota
|
||||
period
|
||||
space
|
||||
)
|
||||
last := space
|
||||
Loop:
|
||||
for i := 0; i < len(s); i++ {
|
||||
b := s[i]
|
||||
switch b {
|
||||
case ' ', '\t', '\r', '\n':
|
||||
switch last {
|
||||
case period:
|
||||
break Loop
|
||||
case other:
|
||||
buf = append(buf, ' ')
|
||||
last = space
|
||||
}
|
||||
case '.':
|
||||
last = period
|
||||
buf = append(buf, b)
|
||||
default:
|
||||
last = other
|
||||
buf = append(buf, b)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that synopsis fits an App Engine datastore text property.
|
||||
const m = 400
|
||||
if len(buf) > m {
|
||||
buf = buf[:m]
|
||||
if i := bytes.LastIndex(buf, []byte{' '}); i >= 0 {
|
||||
buf = buf[:i]
|
||||
}
|
||||
buf = append(buf, " ..."...)
|
||||
}
|
||||
|
||||
s = string(buf)
|
||||
|
||||
r, n := utf8.DecodeRuneInString(s)
|
||||
if n < 0 || unicode.IsPunct(r) || unicode.IsSymbol(r) {
|
||||
// ignore Markdown headings, editor settings, Go build constraints, and * in poorly formatted block comments.
|
||||
s = ""
|
||||
} else {
|
||||
for _, prefix := range badSynopsisPrefixes {
|
||||
if strings.HasPrefix(s, prefix) {
|
||||
s = ""
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
var referencesPats = []*regexp.Regexp{
|
||||
regexp.MustCompile(`"([-a-zA-Z0-9~+_./]+)"`), // quoted path
|
||||
regexp.MustCompile(`https://drone\.io/([-a-zA-Z0-9~+_./]+)/status\.png`),
|
||||
regexp.MustCompile(`\b(?:` + strings.Join([]string{
|
||||
`go\s+get\s+`,
|
||||
`goinstall\s+`,
|
||||
regexp.QuoteMeta("http://godoc.org/"),
|
||||
regexp.QuoteMeta("http://gopkgdoc.appspot.com/pkg/"),
|
||||
regexp.QuoteMeta("http://go.pkgdoc.org/"),
|
||||
regexp.QuoteMeta("http://gowalker.org/"),
|
||||
}, "|") + `)([-a-zA-Z0-9~+_./]+)`),
|
||||
}
|
||||
|
||||
// addReferences adds packages referenced in plain text s.
|
||||
func addReferences(references map[string]bool, s []byte) {
|
||||
for _, pat := range referencesPats {
|
||||
for _, m := range pat.FindAllSubmatch(s, -1) {
|
||||
p := string(m[1])
|
||||
if gosrc.IsValidRemotePath(p) {
|
||||
references[p] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type byFuncName []*doc.Func
|
||||
|
||||
func (s byFuncName) Len() int { return len(s) }
|
||||
func (s byFuncName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s byFuncName) Less(i, j int) bool { return s[i].Name < s[j].Name }
|
||||
|
||||
func removeAssociations(dpkg *doc.Package) {
|
||||
for _, t := range dpkg.Types {
|
||||
dpkg.Funcs = append(dpkg.Funcs, t.Funcs...)
|
||||
t.Funcs = nil
|
||||
}
|
||||
sort.Sort(byFuncName(dpkg.Funcs))
|
||||
}
|
||||
|
||||
// builder holds the state used when building the documentation.
|
||||
type builder struct {
|
||||
srcs map[string]*source
|
||||
fset *token.FileSet
|
||||
examples []*doc.Example
|
||||
buf []byte // scratch space for printNode method.
|
||||
}
|
||||
|
||||
type Value struct {
|
||||
Decl Code
|
||||
Pos Pos
|
||||
Doc string
|
||||
}
|
||||
|
||||
func (b *builder) values(vdocs []*doc.Value) []*Value {
|
||||
var result []*Value
|
||||
for _, d := range vdocs {
|
||||
result = append(result, &Value{
|
||||
Decl: b.printDecl(d.Decl),
|
||||
Pos: b.position(d.Decl),
|
||||
Doc: d.Doc,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type Note struct {
|
||||
Pos Pos
|
||||
UID string
|
||||
Body string
|
||||
}
|
||||
|
||||
type posNode token.Pos
|
||||
|
||||
func (p posNode) Pos() token.Pos { return token.Pos(p) }
|
||||
func (p posNode) End() token.Pos { return token.Pos(p) }
|
||||
|
||||
func (b *builder) notes(gnotes map[string][]*doc.Note) map[string][]*Note {
|
||||
if len(gnotes) == 0 {
|
||||
return nil
|
||||
}
|
||||
notes := make(map[string][]*Note)
|
||||
for tag, gvalues := range gnotes {
|
||||
values := make([]*Note, len(gvalues))
|
||||
for i := range gvalues {
|
||||
values[i] = &Note{
|
||||
Pos: b.position(posNode(gvalues[i].Pos)),
|
||||
UID: gvalues[i].UID,
|
||||
Body: strings.TrimSpace(gvalues[i].Body),
|
||||
}
|
||||
}
|
||||
notes[tag] = values
|
||||
}
|
||||
return notes
|
||||
}
|
||||
|
||||
type Example struct {
|
||||
Name string
|
||||
Doc string
|
||||
Code Code
|
||||
Play string
|
||||
Output string
|
||||
}
|
||||
|
||||
var exampleOutputRx = regexp.MustCompile(`(?i)//[[:space:]]*output:`)
|
||||
|
||||
func (b *builder) getExamples(name string) []*Example {
|
||||
var docs []*Example
|
||||
for _, e := range b.examples {
|
||||
if !strings.HasPrefix(e.Name, name) {
|
||||
continue
|
||||
}
|
||||
n := e.Name[len(name):]
|
||||
if n != "" {
|
||||
if i := strings.LastIndex(n, "_"); i != 0 {
|
||||
continue
|
||||
}
|
||||
n = n[1:]
|
||||
if startsWithUppercase(n) {
|
||||
continue
|
||||
}
|
||||
n = strings.Title(n)
|
||||
}
|
||||
|
||||
code, output := b.printExample(e)
|
||||
|
||||
play := ""
|
||||
if e.Play != nil {
|
||||
b.buf = b.buf[:0]
|
||||
if err := format.Node(sliceWriter{&b.buf}, b.fset, e.Play); err != nil {
|
||||
play = err.Error()
|
||||
} else {
|
||||
play = string(b.buf)
|
||||
}
|
||||
}
|
||||
|
||||
docs = append(docs, &Example{
|
||||
Name: n,
|
||||
Doc: e.Doc,
|
||||
Code: code,
|
||||
Output: output,
|
||||
Play: play})
|
||||
}
|
||||
return docs
|
||||
}
|
||||
|
||||
type Func struct {
|
||||
Decl Code
|
||||
Pos Pos
|
||||
Doc string
|
||||
Name string
|
||||
Recv string // Actual receiver "T" or "*T".
|
||||
Orig string // Original receiver "T" or "*T". This can be different from Recv due to embedding.
|
||||
Examples []*Example
|
||||
}
|
||||
|
||||
func (b *builder) funcs(fdocs []*doc.Func) []*Func {
|
||||
var result []*Func
|
||||
for _, d := range fdocs {
|
||||
var exampleName string
|
||||
switch {
|
||||
case d.Recv == "":
|
||||
exampleName = d.Name
|
||||
case d.Recv[0] == '*':
|
||||
exampleName = d.Recv[1:] + "_" + d.Name
|
||||
default:
|
||||
exampleName = d.Recv + "_" + d.Name
|
||||
}
|
||||
result = append(result, &Func{
|
||||
Decl: b.printDecl(d.Decl),
|
||||
Pos: b.position(d.Decl),
|
||||
Doc: d.Doc,
|
||||
Name: d.Name,
|
||||
Recv: d.Recv,
|
||||
Orig: d.Orig,
|
||||
Examples: b.getExamples(exampleName),
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type Type struct {
|
||||
Doc string
|
||||
Name string
|
||||
Decl Code
|
||||
Pos Pos
|
||||
Consts []*Value
|
||||
Vars []*Value
|
||||
Funcs []*Func
|
||||
Methods []*Func
|
||||
Examples []*Example
|
||||
}
|
||||
|
||||
func (b *builder) types(tdocs []*doc.Type) []*Type {
|
||||
var result []*Type
|
||||
for _, d := range tdocs {
|
||||
result = append(result, &Type{
|
||||
Doc: d.Doc,
|
||||
Name: d.Name,
|
||||
Decl: b.printDecl(d.Decl),
|
||||
Pos: b.position(d.Decl),
|
||||
Consts: b.values(d.Consts),
|
||||
Vars: b.values(d.Vars),
|
||||
Funcs: b.funcs(d.Funcs),
|
||||
Methods: b.funcs(d.Methods),
|
||||
Examples: b.getExamples(d.Name),
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
var packageNamePats = []*regexp.Regexp{
|
||||
// Last element with .suffix removed.
|
||||
regexp.MustCompile(`/([^-./]+)[-.](?:git|svn|hg|bzr|v\d+)$`),
|
||||
|
||||
// Last element with "go" prefix or suffix removed.
|
||||
regexp.MustCompile(`/([^-./]+)[-.]go$`),
|
||||
regexp.MustCompile(`/go[-.]([^-./]+)$`),
|
||||
|
||||
// Special cases for popular repos.
|
||||
regexp.MustCompile(`^code\.google\.com/p/google-api-go-client/([^/]+)/v[^/]+$`),
|
||||
regexp.MustCompile(`^code\.google\.com/p/biogo\.([^/]+)$`),
|
||||
|
||||
// It's also common for the last element of the path to contain an
|
||||
// extra "go" prefix, but not always. TODO: examine unresolved ids to
|
||||
// detect when trimming the "go" prefix is appropriate.
|
||||
|
||||
// Last component of path.
|
||||
regexp.MustCompile(`([^/]+)$`),
|
||||
}
|
||||
|
||||
func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
|
||||
pkg := imports[path]
|
||||
if pkg != nil {
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
// Guess the package name without importing it.
|
||||
for _, pat := range packageNamePats {
|
||||
m := pat.FindStringSubmatch(path)
|
||||
if m != nil {
|
||||
pkg = ast.NewObj(ast.Pkg, m[1])
|
||||
pkg.Data = ast.NewScope(nil)
|
||||
imports[path] = pkg
|
||||
return pkg, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("package not found")
|
||||
}
|
||||
|
||||
type File struct {
|
||||
Name string
|
||||
URL string
|
||||
}
|
||||
|
||||
type Pos struct {
|
||||
Line int32 // 0 if not valid.
|
||||
N uint16 // number of lines - 1
|
||||
File int16 // index in Package.Files
|
||||
}
|
||||
|
||||
type source struct {
|
||||
name string
|
||||
browseURL string
|
||||
data []byte
|
||||
index int
|
||||
}
|
||||
|
||||
// PackageVersion is modified when previously stored packages are invalid.
|
||||
const PackageVersion = "8"
|
||||
|
||||
type Package struct {
|
||||
// The import path for this package.
|
||||
ImportPath string
|
||||
|
||||
// Import path prefix for all packages in the project.
|
||||
ProjectRoot string
|
||||
|
||||
// Name of the project.
|
||||
ProjectName string
|
||||
|
||||
// Project home page.
|
||||
ProjectURL string
|
||||
|
||||
// Errors found when fetching or parsing this package.
|
||||
Errors []string
|
||||
|
||||
// Packages referenced in README files.
|
||||
References []string
|
||||
|
||||
// Version control system: git, hg, bzr, ...
|
||||
VCS string
|
||||
|
||||
// Version control: active or suppressed.
|
||||
Status gosrc.DirectoryStatus
|
||||
|
||||
// Whether the package is a fork of another one.
|
||||
Fork bool
|
||||
|
||||
// How many stars (for a GitHub project) or followers (for a BitBucket
|
||||
// project) the repository of this package has.
|
||||
Stars int
|
||||
|
||||
// The time this object was created.
|
||||
Updated time.Time
|
||||
|
||||
// Cache validation tag. This tag is not necessarily an HTTP entity tag.
|
||||
// The tag is "" if there is no meaningful cache validation for the VCS.
|
||||
Etag string
|
||||
|
||||
// Subdirectories, possibly containing Go code.
|
||||
Subdirectories []string
|
||||
|
||||
// Package name or "" if no package for this import path. The proceeding
|
||||
// fields are set even if a package is not found for the import path.
|
||||
Name string
|
||||
|
||||
// Synopsis and full documentation for the package.
|
||||
Synopsis string
|
||||
Doc string
|
||||
|
||||
// Format this package as a command.
|
||||
IsCmd bool
|
||||
|
||||
// True if package documentation is incomplete.
|
||||
Truncated bool
|
||||
|
||||
// Environment
|
||||
GOOS, GOARCH string
|
||||
|
||||
// Top-level declarations.
|
||||
Consts []*Value
|
||||
Funcs []*Func
|
||||
Types []*Type
|
||||
Vars []*Value
|
||||
|
||||
// Package examples
|
||||
Examples []*Example
|
||||
|
||||
Notes map[string][]*Note
|
||||
|
||||
// Source.
|
||||
LineFmt string
|
||||
BrowseURL string
|
||||
Files []*File
|
||||
TestFiles []*File
|
||||
|
||||
// Source size in bytes.
|
||||
SourceSize int
|
||||
TestSourceSize int
|
||||
|
||||
// Imports
|
||||
Imports []string
|
||||
TestImports []string
|
||||
XTestImports []string
|
||||
}
|
||||
|
||||
var goEnvs = []struct{ GOOS, GOARCH string }{
|
||||
{"linux", "amd64"},
|
||||
{"darwin", "amd64"},
|
||||
{"windows", "amd64"},
|
||||
{"linux", "js"},
|
||||
}
|
||||
|
||||
// SetDefaultGOOS sets given GOOS value as default one to use when building
|
||||
// package documents. SetDefaultGOOS has no effect on some windows-only
|
||||
// packages.
|
||||
func SetDefaultGOOS(goos string) {
|
||||
if goos == "" {
|
||||
return
|
||||
}
|
||||
var i int
|
||||
for ; i < len(goEnvs); i++ {
|
||||
if goEnvs[i].GOOS == goos {
|
||||
break
|
||||
}
|
||||
}
|
||||
switch i {
|
||||
case 0:
|
||||
return
|
||||
case len(goEnvs):
|
||||
env := goEnvs[0]
|
||||
env.GOOS = goos
|
||||
goEnvs = append(goEnvs, env)
|
||||
}
|
||||
goEnvs[0], goEnvs[i] = goEnvs[i], goEnvs[0]
|
||||
}
|
||||
|
||||
var windowsOnlyPackages = map[string]bool{
|
||||
"internal/syscall/windows": true,
|
||||
"internal/syscall/windows/registry": true,
|
||||
"golang.org/x/exp/shiny/driver/internal/win32": true,
|
||||
"golang.org/x/exp/shiny/driver/windriver": true,
|
||||
"golang.org/x/sys/windows": true,
|
||||
"golang.org/x/sys/windows/registry": true,
|
||||
}
|
||||
|
||||
func newPackage(dir *gosrc.Directory) (*Package, error) {
|
||||
|
||||
pkg := &Package{
|
||||
Updated: time.Now().UTC(),
|
||||
LineFmt: dir.LineFmt,
|
||||
ImportPath: dir.ImportPath,
|
||||
ProjectRoot: dir.ProjectRoot,
|
||||
ProjectName: dir.ProjectName,
|
||||
ProjectURL: dir.ProjectURL,
|
||||
BrowseURL: dir.BrowseURL,
|
||||
Etag: PackageVersion + "-" + dir.Etag,
|
||||
VCS: dir.VCS,
|
||||
Status: dir.Status,
|
||||
Subdirectories: dir.Subdirectories,
|
||||
Fork: dir.Fork,
|
||||
Stars: dir.Stars,
|
||||
}
|
||||
|
||||
var b builder
|
||||
b.srcs = make(map[string]*source)
|
||||
references := make(map[string]bool)
|
||||
for _, file := range dir.Files {
|
||||
if strings.HasSuffix(file.Name, ".go") {
|
||||
gosrc.OverwriteLineComments(file.Data)
|
||||
b.srcs[file.Name] = &source{name: file.Name, browseURL: file.BrowseURL, data: file.Data}
|
||||
} else {
|
||||
addReferences(references, file.Data)
|
||||
}
|
||||
}
|
||||
|
||||
for r := range references {
|
||||
pkg.References = append(pkg.References, r)
|
||||
}
|
||||
|
||||
if len(b.srcs) == 0 {
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
b.fset = token.NewFileSet()
|
||||
|
||||
// Find the package and associated files.
|
||||
|
||||
ctxt := build.Context{
|
||||
GOOS: "linux",
|
||||
GOARCH: "amd64",
|
||||
CgoEnabled: true,
|
||||
ReleaseTags: build.Default.ReleaseTags,
|
||||
BuildTags: build.Default.BuildTags,
|
||||
Compiler: "gc",
|
||||
}
|
||||
|
||||
var err error
|
||||
var bpkg *build.Package
|
||||
|
||||
for _, env := range goEnvs {
|
||||
// Some packages should be always displayed as GOOS=windows (see issue #16509 for details).
|
||||
// TODO: remove this once issue #16509 is resolved.
|
||||
if windowsOnlyPackages[dir.ImportPath] && env.GOOS != "windows" {
|
||||
continue
|
||||
}
|
||||
|
||||
ctxt.GOOS = env.GOOS
|
||||
ctxt.GOARCH = env.GOARCH
|
||||
bpkg, err = dir.Import(&ctxt, build.ImportComment)
|
||||
if _, ok := err.(*build.NoGoError); !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if _, ok := err.(*build.NoGoError); !ok {
|
||||
pkg.Errors = append(pkg.Errors, err.Error())
|
||||
}
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
if bpkg.ImportComment != "" && bpkg.ImportComment != dir.ImportPath {
|
||||
return nil, gosrc.NotFoundError{
|
||||
Message: "not at canonical import path",
|
||||
Redirect: bpkg.ImportComment,
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the Go files
|
||||
|
||||
files := make(map[string]*ast.File)
|
||||
names := append(bpkg.GoFiles, bpkg.CgoFiles...)
|
||||
sort.Strings(names)
|
||||
pkg.Files = make([]*File, len(names))
|
||||
for i, name := range names {
|
||||
file, err := parser.ParseFile(b.fset, name, b.srcs[name].data, parser.ParseComments)
|
||||
if err != nil {
|
||||
pkg.Errors = append(pkg.Errors, err.Error())
|
||||
} else {
|
||||
files[name] = file
|
||||
}
|
||||
src := b.srcs[name]
|
||||
src.index = i
|
||||
pkg.Files[i] = &File{Name: name, URL: src.browseURL}
|
||||
pkg.SourceSize += len(src.data)
|
||||
}
|
||||
|
||||
apkg, _ := ast.NewPackage(b.fset, files, simpleImporter, nil)
|
||||
|
||||
// Find examples in the test files.
|
||||
|
||||
names = append(bpkg.TestGoFiles, bpkg.XTestGoFiles...)
|
||||
sort.Strings(names)
|
||||
pkg.TestFiles = make([]*File, len(names))
|
||||
for i, name := range names {
|
||||
file, err := parser.ParseFile(b.fset, name, b.srcs[name].data, parser.ParseComments)
|
||||
if err != nil {
|
||||
pkg.Errors = append(pkg.Errors, err.Error())
|
||||
} else {
|
||||
b.examples = append(b.examples, doc.Examples(file)...)
|
||||
}
|
||||
pkg.TestFiles[i] = &File{Name: name, URL: b.srcs[name].browseURL}
|
||||
pkg.TestSourceSize += len(b.srcs[name].data)
|
||||
}
|
||||
|
||||
b.vetPackage(pkg, apkg)
|
||||
|
||||
mode := doc.Mode(0)
|
||||
if pkg.ImportPath == "builtin" {
|
||||
mode |= doc.AllDecls
|
||||
}
|
||||
|
||||
dpkg := doc.New(apkg, pkg.ImportPath, mode)
|
||||
|
||||
if pkg.ImportPath == "builtin" {
|
||||
removeAssociations(dpkg)
|
||||
}
|
||||
|
||||
pkg.Name = dpkg.Name
|
||||
pkg.Doc = strings.TrimRight(dpkg.Doc, " \t\n\r")
|
||||
pkg.Synopsis = synopsis(pkg.Doc)
|
||||
|
||||
pkg.Examples = b.getExamples("")
|
||||
pkg.IsCmd = bpkg.IsCommand()
|
||||
pkg.GOOS = ctxt.GOOS
|
||||
pkg.GOARCH = ctxt.GOARCH
|
||||
|
||||
pkg.Consts = b.values(dpkg.Consts)
|
||||
pkg.Funcs = b.funcs(dpkg.Funcs)
|
||||
pkg.Types = b.types(dpkg.Types)
|
||||
pkg.Vars = b.values(dpkg.Vars)
|
||||
pkg.Notes = b.notes(dpkg.Notes)
|
||||
|
||||
pkg.Imports = bpkg.Imports
|
||||
pkg.TestImports = bpkg.TestImports
|
||||
pkg.XTestImports = bpkg.XTestImports
|
||||
|
||||
return pkg, nil
|
||||
}
|
114
vendor/github.com/golang/gddo/doc/builder_test.go
generated
vendored
Normal file
114
vendor/github.com/golang/gddo/doc/builder_test.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
// 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
package doc
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var badSynopsis = []string{
|
||||
"+build !release",
|
||||
"COPYRIGHT Jimmy Bob",
|
||||
"### Markdown heading",
|
||||
"-*- indent-tabs-mode: nil -*-",
|
||||
"vim:set ts=2 sw=2 et ai ft=go:",
|
||||
}
|
||||
|
||||
func TestBadSynopsis(t *testing.T) {
|
||||
for _, s := range badSynopsis {
|
||||
if synopsis(s) != "" {
|
||||
t.Errorf(`synopsis(%q) did not return ""`, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const readme = `
|
||||
$ go get github.com/user/repo/pkg1
|
||||
[foo](http://gopkgdoc.appspot.com/pkg/github.com/user/repo/pkg2)
|
||||
[foo](http://go.pkgdoc.org/github.com/user/repo/pkg3)
|
||||
[foo](http://godoc.org/github.com/user/repo/pkg4)
|
||||
<http://go.pkgdoc.org/github.com/user/repo/pkg5>
|
||||
[foo](http://godoc.org/github.com/user/repo/pkg6#Export)
|
||||
http://gowalker.org/github.com/user/repo/pkg7
|
||||
Build Status: [](https://drone.io/github.com/user/repo1/latest)
|
||||
'go get example.org/package1' will install package1.
|
||||
(http://go.pkgdoc.org/example.org/package2 "Package2's documentation on GoPkgDoc").
|
||||
import "example.org/package3"
|
||||
`
|
||||
|
||||
var expectedReferences = []string{
|
||||
"github.com/user/repo/pkg1",
|
||||
"github.com/user/repo/pkg2",
|
||||
"github.com/user/repo/pkg3",
|
||||
"github.com/user/repo/pkg4",
|
||||
"github.com/user/repo/pkg5",
|
||||
"github.com/user/repo/pkg6",
|
||||
"github.com/user/repo/pkg7",
|
||||
"github.com/user/repo1",
|
||||
"example.org/package1",
|
||||
"example.org/package2",
|
||||
"example.org/package3",
|
||||
}
|
||||
|
||||
func TestReferences(t *testing.T) {
|
||||
references := make(map[string]bool)
|
||||
addReferences(references, []byte(readme))
|
||||
for _, r := range expectedReferences {
|
||||
if !references[r] {
|
||||
t.Errorf("missing %s", r)
|
||||
}
|
||||
delete(references, r)
|
||||
}
|
||||
for r := range references {
|
||||
t.Errorf("extra %s", r)
|
||||
}
|
||||
}
|
||||
|
||||
var simpleImporterTests = []struct {
|
||||
path string
|
||||
name string
|
||||
}{
|
||||
// Last element with .suffix removed.
|
||||
{"example.com/user/name.git", "name"},
|
||||
{"example.com/user/name.svn", "name"},
|
||||
{"example.com/user/name.hg", "name"},
|
||||
{"example.com/user/name.bzr", "name"},
|
||||
{"example.com/name.v0", "name"},
|
||||
{"example.com/user/repo/name.v11", "name"},
|
||||
|
||||
// Last element with "go" prefix or suffix removed.
|
||||
{"github.com/user/go-name", "name"},
|
||||
{"github.com/user/go.name", "name"},
|
||||
{"github.com/user/name.go", "name"},
|
||||
{"github.com/user/name-go", "name"},
|
||||
|
||||
// Special cases for popular repos.
|
||||
{"code.google.com/p/biogo.name", "name"},
|
||||
{"code.google.com/p/google-api-go-client/name/v3", "name"},
|
||||
|
||||
// Use last element of path.
|
||||
{"example.com/user/name.other", "name.other"},
|
||||
{"example.com/.v0", ".v0"},
|
||||
{"example.com/user/repo.v2/name", "name"},
|
||||
{"github.com/user/namev0", "namev0"},
|
||||
{"github.com/user/goname", "goname"},
|
||||
{"github.com/user/namego", "namego"},
|
||||
{"github.com/user/name", "name"},
|
||||
{"name", "name"},
|
||||
{"user/name", "name"},
|
||||
}
|
||||
|
||||
func TestSimpleImporter(t *testing.T) {
|
||||
for _, tt := range simpleImporterTests {
|
||||
m := make(map[string]*ast.Object)
|
||||
obj, _ := simpleImporter(m, tt.path)
|
||||
if obj.Name != tt.name {
|
||||
t.Errorf("simpleImporter(%q) = %q, want %q", tt.path, obj.Name, tt.name)
|
||||
}
|
||||
}
|
||||
}
|
359
vendor/github.com/golang/gddo/doc/code.go
generated
vendored
Normal file
359
vendor/github.com/golang/gddo/doc/code.go
generated
vendored
Normal file
@@ -0,0 +1,359 @@
|
||||
// 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
package doc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/doc"
|
||||
"go/printer"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
notPredeclared = iota
|
||||
predeclaredType
|
||||
predeclaredConstant
|
||||
predeclaredFunction
|
||||
)
|
||||
|
||||
// predeclared represents the set of all predeclared identifiers.
|
||||
var predeclared = map[string]int{
|
||||
"bool": predeclaredType,
|
||||
"byte": predeclaredType,
|
||||
"complex128": predeclaredType,
|
||||
"complex64": predeclaredType,
|
||||
"error": predeclaredType,
|
||||
"float32": predeclaredType,
|
||||
"float64": predeclaredType,
|
||||
"int16": predeclaredType,
|
||||
"int32": predeclaredType,
|
||||
"int64": predeclaredType,
|
||||
"int8": predeclaredType,
|
||||
"int": predeclaredType,
|
||||
"rune": predeclaredType,
|
||||
"string": predeclaredType,
|
||||
"uint16": predeclaredType,
|
||||
"uint32": predeclaredType,
|
||||
"uint64": predeclaredType,
|
||||
"uint8": predeclaredType,
|
||||
"uint": predeclaredType,
|
||||
"uintptr": predeclaredType,
|
||||
|
||||
"true": predeclaredConstant,
|
||||
"false": predeclaredConstant,
|
||||
"iota": predeclaredConstant,
|
||||
"nil": predeclaredConstant,
|
||||
|
||||
"append": predeclaredFunction,
|
||||
"cap": predeclaredFunction,
|
||||
"close": predeclaredFunction,
|
||||
"complex": predeclaredFunction,
|
||||
"copy": predeclaredFunction,
|
||||
"delete": predeclaredFunction,
|
||||
"imag": predeclaredFunction,
|
||||
"len": predeclaredFunction,
|
||||
"make": predeclaredFunction,
|
||||
"new": predeclaredFunction,
|
||||
"panic": predeclaredFunction,
|
||||
"print": predeclaredFunction,
|
||||
"println": predeclaredFunction,
|
||||
"real": predeclaredFunction,
|
||||
"recover": predeclaredFunction,
|
||||
}
|
||||
|
||||
type AnnotationKind int16
|
||||
|
||||
const (
|
||||
// Link to export in package specified by Paths[PathIndex] with fragment
|
||||
// Text[strings.LastIndex(Text[Pos:End], ".")+1:End].
|
||||
LinkAnnotation AnnotationKind = iota
|
||||
|
||||
// Anchor with name specified by Text[Pos:End] or typeName + "." +
|
||||
// Text[Pos:End] for type declarations.
|
||||
AnchorAnnotation
|
||||
|
||||
// Comment.
|
||||
CommentAnnotation
|
||||
|
||||
// Link to package specified by Paths[PathIndex].
|
||||
PackageLinkAnnotation
|
||||
|
||||
// Link to builtin entity with name Text[Pos:End].
|
||||
BuiltinAnnotation
|
||||
)
|
||||
|
||||
type Annotation struct {
|
||||
Pos, End int32
|
||||
Kind AnnotationKind
|
||||
PathIndex int16
|
||||
}
|
||||
|
||||
type Code struct {
|
||||
Text string
|
||||
Annotations []Annotation
|
||||
Paths []string
|
||||
}
|
||||
|
||||
// declVisitor modifies a declaration AST for printing and collects annotations.
|
||||
type declVisitor struct {
|
||||
annotations []Annotation
|
||||
paths []string
|
||||
pathIndex map[string]int
|
||||
comments []*ast.CommentGroup
|
||||
}
|
||||
|
||||
func (v *declVisitor) add(kind AnnotationKind, importPath string) {
|
||||
pathIndex := -1
|
||||
if importPath != "" {
|
||||
var ok bool
|
||||
pathIndex, ok = v.pathIndex[importPath]
|
||||
if !ok {
|
||||
pathIndex = len(v.paths)
|
||||
v.paths = append(v.paths, importPath)
|
||||
v.pathIndex[importPath] = pathIndex
|
||||
}
|
||||
}
|
||||
v.annotations = append(v.annotations, Annotation{Kind: kind, PathIndex: int16(pathIndex)})
|
||||
}
|
||||
|
||||
func (v *declVisitor) ignoreName() {
|
||||
v.add(-1, "")
|
||||
}
|
||||
|
||||
func (v *declVisitor) Visit(n ast.Node) ast.Visitor {
|
||||
switch n := n.(type) {
|
||||
case *ast.TypeSpec:
|
||||
v.ignoreName()
|
||||
switch n := n.Type.(type) {
|
||||
case *ast.InterfaceType:
|
||||
for _, f := range n.Methods.List {
|
||||
for _ = range f.Names {
|
||||
v.add(AnchorAnnotation, "")
|
||||
}
|
||||
ast.Walk(v, f.Type)
|
||||
}
|
||||
case *ast.StructType:
|
||||
for _, f := range n.Fields.List {
|
||||
for _ = range f.Names {
|
||||
v.add(AnchorAnnotation, "")
|
||||
}
|
||||
ast.Walk(v, f.Type)
|
||||
}
|
||||
default:
|
||||
ast.Walk(v, n)
|
||||
}
|
||||
case *ast.FuncDecl:
|
||||
if n.Recv != nil {
|
||||
ast.Walk(v, n.Recv)
|
||||
}
|
||||
v.ignoreName()
|
||||
ast.Walk(v, n.Type)
|
||||
case *ast.Field:
|
||||
for _ = range n.Names {
|
||||
v.ignoreName()
|
||||
}
|
||||
ast.Walk(v, n.Type)
|
||||
case *ast.ValueSpec:
|
||||
for _ = range n.Names {
|
||||
v.add(AnchorAnnotation, "")
|
||||
}
|
||||
if n.Type != nil {
|
||||
ast.Walk(v, n.Type)
|
||||
}
|
||||
for _, x := range n.Values {
|
||||
ast.Walk(v, x)
|
||||
}
|
||||
case *ast.Ident:
|
||||
switch {
|
||||
case n.Obj == nil && predeclared[n.Name] != notPredeclared:
|
||||
v.add(BuiltinAnnotation, "")
|
||||
case n.Obj != nil && ast.IsExported(n.Name):
|
||||
v.add(LinkAnnotation, "")
|
||||
default:
|
||||
v.ignoreName()
|
||||
}
|
||||
case *ast.SelectorExpr:
|
||||
if x, _ := n.X.(*ast.Ident); x != nil {
|
||||
if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg {
|
||||
if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil {
|
||||
if path, err := strconv.Unquote(spec.Path.Value); err == nil {
|
||||
v.add(PackageLinkAnnotation, path)
|
||||
if path == "C" {
|
||||
v.ignoreName()
|
||||
} else {
|
||||
v.add(LinkAnnotation, path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.Walk(v, n.X)
|
||||
v.ignoreName()
|
||||
case *ast.BasicLit:
|
||||
if n.Kind == token.STRING && len(n.Value) > 128 {
|
||||
v.comments = append(v.comments,
|
||||
&ast.CommentGroup{List: []*ast.Comment{{
|
||||
Slash: n.Pos(),
|
||||
Text: fmt.Sprintf("/* %d byte string literal not displayed */", len(n.Value)),
|
||||
}}})
|
||||
n.Value = `""`
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
case *ast.CompositeLit:
|
||||
if len(n.Elts) > 100 {
|
||||
if n.Type != nil {
|
||||
ast.Walk(v, n.Type)
|
||||
}
|
||||
v.comments = append(v.comments,
|
||||
&ast.CommentGroup{List: []*ast.Comment{{
|
||||
Slash: n.Lbrace,
|
||||
Text: fmt.Sprintf("/* %d elements not displayed */", len(n.Elts)),
|
||||
}}})
|
||||
n.Elts = n.Elts[:0]
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
default:
|
||||
return v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *builder) printDecl(decl ast.Decl) (d Code) {
|
||||
v := &declVisitor{pathIndex: make(map[string]int)}
|
||||
ast.Walk(v, decl)
|
||||
b.buf = b.buf[:0]
|
||||
err := (&printer.Config{Mode: printer.UseSpaces, Tabwidth: 4}).Fprint(
|
||||
sliceWriter{&b.buf},
|
||||
b.fset,
|
||||
&printer.CommentedNode{Node: decl, Comments: v.comments})
|
||||
if err != nil {
|
||||
return Code{Text: err.Error()}
|
||||
}
|
||||
|
||||
var annotations []Annotation
|
||||
var s scanner.Scanner
|
||||
fset := token.NewFileSet()
|
||||
file := fset.AddFile("", fset.Base(), len(b.buf))
|
||||
s.Init(file, b.buf, nil, scanner.ScanComments)
|
||||
prevTok := token.ILLEGAL
|
||||
loop:
|
||||
for {
|
||||
pos, tok, lit := s.Scan()
|
||||
switch tok {
|
||||
case token.EOF:
|
||||
break loop
|
||||
case token.COMMENT:
|
||||
p := file.Offset(pos)
|
||||
e := p + len(lit)
|
||||
if prevTok == token.COMMENT {
|
||||
annotations[len(annotations)-1].End = int32(e)
|
||||
} else {
|
||||
annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int32(p), End: int32(e)})
|
||||
}
|
||||
case token.IDENT:
|
||||
if len(v.annotations) == 0 {
|
||||
// Oops!
|
||||
break loop
|
||||
}
|
||||
annotation := v.annotations[0]
|
||||
v.annotations = v.annotations[1:]
|
||||
if annotation.Kind == -1 {
|
||||
continue
|
||||
}
|
||||
p := file.Offset(pos)
|
||||
e := p + len(lit)
|
||||
annotation.Pos = int32(p)
|
||||
annotation.End = int32(e)
|
||||
annotations = append(annotations, annotation)
|
||||
}
|
||||
prevTok = tok
|
||||
}
|
||||
return Code{Text: string(b.buf), Annotations: annotations, Paths: v.paths}
|
||||
}
|
||||
|
||||
func (b *builder) position(n ast.Node) Pos {
|
||||
var position Pos
|
||||
pos := b.fset.Position(n.Pos())
|
||||
src := b.srcs[pos.Filename]
|
||||
if src != nil {
|
||||
position.File = int16(src.index)
|
||||
position.Line = int32(pos.Line)
|
||||
end := b.fset.Position(n.End())
|
||||
if src == b.srcs[end.Filename] {
|
||||
n := end.Line - pos.Line
|
||||
if n >= 0 && n <= math.MaxUint16 {
|
||||
position.N = uint16(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
return position
|
||||
}
|
||||
|
||||
func (b *builder) printExample(e *doc.Example) (code Code, output string) {
|
||||
output = e.Output
|
||||
|
||||
b.buf = b.buf[:0]
|
||||
var n interface{}
|
||||
if _, ok := e.Code.(*ast.File); ok {
|
||||
n = e.Play
|
||||
} else {
|
||||
n = &printer.CommentedNode{Node: e.Code, Comments: e.Comments}
|
||||
}
|
||||
err := (&printer.Config{Mode: printer.UseSpaces, Tabwidth: 4}).Fprint(sliceWriter{&b.buf}, b.fset, n)
|
||||
if err != nil {
|
||||
return Code{Text: err.Error()}, output
|
||||
}
|
||||
|
||||
// additional formatting if this is a function body
|
||||
if i := len(b.buf); i >= 2 && b.buf[0] == '{' && b.buf[i-1] == '}' {
|
||||
// remove surrounding braces
|
||||
b.buf = b.buf[1 : i-1]
|
||||
// unindent
|
||||
b.buf = bytes.Replace(b.buf, []byte("\n "), []byte("\n"), -1)
|
||||
// remove output comment
|
||||
if j := exampleOutputRx.FindIndex(b.buf); j != nil {
|
||||
b.buf = bytes.TrimSpace(b.buf[:j[0]])
|
||||
}
|
||||
} else {
|
||||
// drop output, as the output comment will appear in the code
|
||||
output = ""
|
||||
}
|
||||
|
||||
var annotations []Annotation
|
||||
var s scanner.Scanner
|
||||
fset := token.NewFileSet()
|
||||
file := fset.AddFile("", fset.Base(), len(b.buf))
|
||||
s.Init(file, b.buf, nil, scanner.ScanComments)
|
||||
prevTok := token.ILLEGAL
|
||||
scanLoop:
|
||||
for {
|
||||
pos, tok, lit := s.Scan()
|
||||
switch tok {
|
||||
case token.EOF:
|
||||
break scanLoop
|
||||
case token.COMMENT:
|
||||
p := file.Offset(pos)
|
||||
e := p + len(lit)
|
||||
if prevTok == token.COMMENT {
|
||||
annotations[len(annotations)-1].End = int32(e)
|
||||
} else {
|
||||
annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int32(p), End: int32(e)})
|
||||
}
|
||||
}
|
||||
prevTok = tok
|
||||
}
|
||||
|
||||
return Code{Text: string(b.buf), Annotations: annotations}, output
|
||||
}
|
55
vendor/github.com/golang/gddo/doc/get.go
generated
vendored
Normal file
55
vendor/github.com/golang/gddo/doc/get.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
// Package doc fetches Go package documentation from version control services.
|
||||
package doc
|
||||
|
||||
import (
|
||||
"github.com/golang/gddo/gosrc"
|
||||
"go/doc"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Get(client *http.Client, importPath string, etag string) (*Package, error) {
|
||||
|
||||
const versionPrefix = PackageVersion + "-"
|
||||
|
||||
if strings.HasPrefix(etag, versionPrefix) {
|
||||
etag = etag[len(versionPrefix):]
|
||||
} else {
|
||||
etag = ""
|
||||
}
|
||||
|
||||
dir, err := gosrc.Get(client, importPath, etag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pdoc, err := newPackage(dir)
|
||||
if err != nil {
|
||||
return pdoc, err
|
||||
}
|
||||
|
||||
if pdoc.Synopsis == "" &&
|
||||
pdoc.Doc == "" &&
|
||||
!pdoc.IsCmd &&
|
||||
pdoc.Name != "" &&
|
||||
dir.ImportPath == dir.ProjectRoot &&
|
||||
len(pdoc.Errors) == 0 {
|
||||
project, err := gosrc.GetProject(client, dir.ResolvedPath)
|
||||
switch {
|
||||
case err == nil:
|
||||
pdoc.Synopsis = doc.Synopsis(project.Description)
|
||||
case gosrc.IsNotFound(err):
|
||||
// ok
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return pdoc, nil
|
||||
}
|
69
vendor/github.com/golang/gddo/doc/goprint.go
generated
vendored
Normal file
69
vendor/github.com/golang/gddo/doc/goprint.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
// 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
// +build ignore
|
||||
|
||||
// Command astprint prints the AST for a file.
|
||||
//
|
||||
// Usage: go run asprint.go fname
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/doc"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
func importer(imports map[string]*ast.Object, path string) (*ast.Object, error) {
|
||||
pkg := imports[path]
|
||||
if pkg == nil {
|
||||
name := path[strings.LastIndex(path, "/")+1:]
|
||||
pkg = ast.NewObj(ast.Pkg, name)
|
||||
pkg.Data = ast.NewScope(nil) // required by ast.NewPackage for dot-import
|
||||
imports[path] = pkg
|
||||
}
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if len(flag.Args()) != 1 {
|
||||
log.Fatal("Usage: go run goprint.go path")
|
||||
}
|
||||
bpkg, err := build.Default.Import(flag.Args()[0], ".", 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fset := token.NewFileSet()
|
||||
files := make(map[string]*ast.File)
|
||||
for _, fname := range bpkg.GoFiles {
|
||||
p, err := ioutil.ReadFile(filepath.Join(bpkg.SrcRoot, bpkg.ImportPath, fname))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
file, err := parser.ParseFile(fset, fname, p, parser.ParseComments)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
files[fname] = file
|
||||
}
|
||||
c := spew.NewDefaultConfig()
|
||||
c.DisableMethods = true
|
||||
apkg, _ := ast.NewPackage(fset, files, importer, nil)
|
||||
c.Dump(apkg)
|
||||
ast.Print(fset, apkg)
|
||||
dpkg := doc.New(apkg, bpkg.ImportPath, 0)
|
||||
c.Dump(dpkg)
|
||||
}
|
50
vendor/github.com/golang/gddo/doc/print.go
generated
vendored
Normal file
50
vendor/github.com/golang/gddo/doc/print.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
// +build ignore
|
||||
|
||||
// Command print fetches and prints package documentation.
|
||||
//
|
||||
// Usage: go run print.go importPath
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/golang/gddo/doc"
|
||||
"github.com/golang/gddo/gosrc"
|
||||
)
|
||||
|
||||
var (
|
||||
etag = flag.String("etag", "", "Etag")
|
||||
local = flag.Bool("local", false, "Get package from local directory.")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if len(flag.Args()) != 1 {
|
||||
log.Fatal("Usage: go run print.go importPath")
|
||||
}
|
||||
path := flag.Args()[0]
|
||||
|
||||
var (
|
||||
pdoc *doc.Package
|
||||
err error
|
||||
)
|
||||
if *local {
|
||||
gosrc.SetLocalDevMode(os.Getenv("GOPATH"))
|
||||
}
|
||||
pdoc, err = doc.Get(http.DefaultClient, path, *etag)
|
||||
//}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
spew.Dump(pdoc)
|
||||
}
|
14
vendor/github.com/golang/gddo/doc/util.go
generated
vendored
Normal file
14
vendor/github.com/golang/gddo/doc/util.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
package doc
|
||||
|
||||
type sliceWriter struct{ p *[]byte }
|
||||
|
||||
func (w sliceWriter) Write(p []byte) (int, error) {
|
||||
*w.p = append(*w.p, p...)
|
||||
return len(p), nil
|
||||
}
|
81
vendor/github.com/golang/gddo/doc/vet.go
generated
vendored
Normal file
81
vendor/github.com/golang/gddo/doc/vet.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
// 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
package doc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/gddo/gosrc"
|
||||
)
|
||||
|
||||
// This list of deprecated exports is used to find code that has not been
|
||||
// updated for Go 1.
|
||||
var deprecatedExports = map[string][]string{
|
||||
`"bytes"`: {"Add"},
|
||||
`"crypto/aes"`: {"Cipher"},
|
||||
`"crypto/hmac"`: {"NewSHA1", "NewSHA256"},
|
||||
`"crypto/rand"`: {"Seed"},
|
||||
`"encoding/json"`: {"MarshalForHTML"},
|
||||
`"encoding/xml"`: {"Marshaler", "NewParser", "Parser"},
|
||||
`"html"`: {"NewTokenizer", "Parse"},
|
||||
`"image"`: {"Color", "NRGBAColor", "RGBAColor"},
|
||||
`"io"`: {"Copyn"},
|
||||
`"log"`: {"Exitf"},
|
||||
`"math"`: {"Fabs", "Fmax", "Fmod"},
|
||||
`"os"`: {"Envs", "Error", "Getenverror", "NewError", "Time", "UnixSignal", "Wait"},
|
||||
`"reflect"`: {"MapValue", "Typeof"},
|
||||
`"runtime"`: {"UpdateMemStats"},
|
||||
`"strconv"`: {"Atob", "Atof32", "Atof64", "AtofN", "Atoi64", "Atoui", "Atoui64", "Btoui64", "Ftoa64", "Itoa64", "Uitoa", "Uitoa64"},
|
||||
`"time"`: {"LocalTime", "Nanoseconds", "NanosecondsToLocalTime", "Seconds", "SecondsToLocalTime", "SecondsToUTC"},
|
||||
`"unicode/utf8"`: {"NewString"},
|
||||
}
|
||||
|
||||
type vetVisitor struct {
|
||||
errors map[string]token.Pos
|
||||
}
|
||||
|
||||
func (v *vetVisitor) Visit(n ast.Node) ast.Visitor {
|
||||
if sel, ok := n.(*ast.SelectorExpr); ok {
|
||||
if x, _ := sel.X.(*ast.Ident); x != nil {
|
||||
if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg {
|
||||
if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil {
|
||||
for _, name := range deprecatedExports[spec.Path.Value] {
|
||||
if name == sel.Sel.Name {
|
||||
v.errors[fmt.Sprintf("%s.%s not found", spec.Path.Value, sel.Sel.Name)] = n.Pos()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func (b *builder) vetPackage(pkg *Package, apkg *ast.Package) {
|
||||
errors := make(map[string]token.Pos)
|
||||
for _, file := range apkg.Files {
|
||||
for _, is := range file.Imports {
|
||||
importPath, _ := strconv.Unquote(is.Path.Value)
|
||||
if !gosrc.IsValidPath(importPath) &&
|
||||
!strings.HasPrefix(importPath, "exp/") &&
|
||||
!strings.HasPrefix(importPath, "appengine") {
|
||||
errors[fmt.Sprintf("Unrecognized import path %q", importPath)] = is.Pos()
|
||||
}
|
||||
}
|
||||
v := vetVisitor{errors: errors}
|
||||
ast.Walk(&v, file)
|
||||
}
|
||||
for message, pos := range errors {
|
||||
pkg.Errors = append(pkg.Errors,
|
||||
fmt.Sprintf("%s (%s)", message, b.fset.Position(pos)))
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user