Update vendor

This commit is contained in:
Liang Ding 2018-03-13 13:24:04 +08:00
parent 982ef9c07f
commit e39b302bdc
701 changed files with 153459 additions and 16822 deletions

10
vendor/golang.org/x/tools/.gitattributes generated vendored Normal file
View File

@ -0,0 +1,10 @@
# Treat all files in this repo as binary, with no git magic updating
# line endings. Windows users contributing to Go will need to use a
# modern version of git and editors capable of LF line endings.
#
# We'll prevent accidental CRLF line endings from entering the repo
# via the git-review gofmt checks.
#
# See golang.org/issue/9281
* -text

2
vendor/golang.org/x/tools/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
# Add no patterns to .gitignore except for files generated by the build.
last-change

3
vendor/golang.org/x/tools/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.

31
vendor/golang.org/x/tools/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,31 @@
# Contributing to Go
Go is an open source project.
It is the work of hundreds of contributors. We appreciate your help!
## Filing issues
When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
1. What version of Go are you using (`go version`)?
2. What operating system and processor architecture are you using?
3. What did you do?
4. What did you expect to see?
5. What did you see instead?
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
## Contributing code
Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
before sending patches.
**We do not accept GitHub pull requests**
(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
Unless otherwise noted, the Go source files are distributed under
the BSD-style license found in the LICENSE file.

3
vendor/golang.org/x/tools/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.

27
vendor/golang.org/x/tools/README.md generated vendored Normal file
View File

@ -0,0 +1,27 @@
# Go Tools
This subrepository holds the source for various packages and tools that support
the Go programming language.
Some of the tools, `godoc` and `vet` for example, are included in binary Go
distributions.
Others, including the Go `guru` and the test coverage tool, can be fetched with
`go get`.
Packages include a type-checker for Go and an implementation of the
Static Single Assignment form (SSA) representation for Go programs.
## Download/Install
The easiest way to install is to run `go get -u golang.org/x/tools/...`. You can
also manually git clone the repository to `$GOPATH/src/golang.org/x/tools`.
## Report Issues / Send Patches
This repository uses Gerrit for code changes. To learn how to submit changes to
this repository, see https://golang.org/doc/contribute.html.
The main issue tracker for the tools repository is located at
https://github.com/golang/go/issues. Prefix your issue with "x/tools/(your
subdir):" in the subject line, so it is easy to find.

131
vendor/golang.org/x/tools/benchmark/parse/parse.go generated vendored Normal file
View File

@ -0,0 +1,131 @@
// 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.
// Package parse provides support for parsing benchmark results as
// generated by 'go test -bench'.
package parse // import "golang.org/x/tools/benchmark/parse"
import (
"bufio"
"bytes"
"fmt"
"io"
"strconv"
"strings"
)
// Flags used by Benchmark.Measured to indicate
// which measurements a Benchmark contains.
const (
NsPerOp = 1 << iota
MBPerS
AllocedBytesPerOp
AllocsPerOp
)
// Benchmark is one run of a single benchmark.
type Benchmark struct {
Name string // benchmark name
N int // number of iterations
NsPerOp float64 // nanoseconds per iteration
AllocedBytesPerOp uint64 // bytes allocated per iteration
AllocsPerOp uint64 // allocs per iteration
MBPerS float64 // MB processed per second
Measured int // which measurements were recorded
Ord int // ordinal position within a benchmark run
}
// ParseLine extracts a Benchmark from a single line of testing.B
// output.
func ParseLine(line string) (*Benchmark, error) {
fields := strings.Fields(line)
// Two required, positional fields: Name and iterations.
if len(fields) < 2 {
return nil, fmt.Errorf("two fields required, have %d", len(fields))
}
if !strings.HasPrefix(fields[0], "Benchmark") {
return nil, fmt.Errorf(`first field does not start with "Benchmark"`)
}
n, err := strconv.Atoi(fields[1])
if err != nil {
return nil, err
}
b := &Benchmark{Name: fields[0], N: n}
// Parse any remaining pairs of fields; we've parsed one pair already.
for i := 1; i < len(fields)/2; i++ {
b.parseMeasurement(fields[i*2], fields[i*2+1])
}
return b, nil
}
func (b *Benchmark) parseMeasurement(quant string, unit string) {
switch unit {
case "ns/op":
if f, err := strconv.ParseFloat(quant, 64); err == nil {
b.NsPerOp = f
b.Measured |= NsPerOp
}
case "MB/s":
if f, err := strconv.ParseFloat(quant, 64); err == nil {
b.MBPerS = f
b.Measured |= MBPerS
}
case "B/op":
if i, err := strconv.ParseUint(quant, 10, 64); err == nil {
b.AllocedBytesPerOp = i
b.Measured |= AllocedBytesPerOp
}
case "allocs/op":
if i, err := strconv.ParseUint(quant, 10, 64); err == nil {
b.AllocsPerOp = i
b.Measured |= AllocsPerOp
}
}
}
func (b *Benchmark) String() string {
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "%s %d", b.Name, b.N)
if (b.Measured & NsPerOp) != 0 {
fmt.Fprintf(buf, " %.2f ns/op", b.NsPerOp)
}
if (b.Measured & MBPerS) != 0 {
fmt.Fprintf(buf, " %.2f MB/s", b.MBPerS)
}
if (b.Measured & AllocedBytesPerOp) != 0 {
fmt.Fprintf(buf, " %d B/op", b.AllocedBytesPerOp)
}
if (b.Measured & AllocsPerOp) != 0 {
fmt.Fprintf(buf, " %d allocs/op", b.AllocsPerOp)
}
return buf.String()
}
// Set is a collection of benchmarks from one
// testing.B run, keyed by name to facilitate comparison.
type Set map[string][]*Benchmark
// ParseSet extracts a Set from testing.B output.
// ParseSet preserves the order of benchmarks that have identical
// names.
func ParseSet(r io.Reader) (Set, error) {
bb := make(Set)
scan := bufio.NewScanner(r)
ord := 0
for scan.Scan() {
if b, err := ParseLine(scan.Text()); err == nil {
b.Ord = ord
ord++
bb[b.Name] = append(bb[b.Name], b)
}
}
if err := scan.Err(); err != nil {
return nil, err
}
return bb, nil
}

154
vendor/golang.org/x/tools/benchmark/parse/parse_test.go generated vendored Normal file
View File

@ -0,0 +1,154 @@
// 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.
package parse
import (
"reflect"
"strings"
"testing"
)
func TestParseLine(t *testing.T) {
cases := []struct {
line string
want *Benchmark
err bool // expect an error
}{
{
line: "BenchmarkEncrypt 100000000 19.6 ns/op",
want: &Benchmark{
Name: "BenchmarkEncrypt",
N: 100000000, NsPerOp: 19.6,
Measured: NsPerOp,
},
},
{
line: "BenchmarkEncrypt 100000000 19.6 ns/op 817.77 MB/s",
want: &Benchmark{
Name: "BenchmarkEncrypt",
N: 100000000, NsPerOp: 19.6, MBPerS: 817.77,
Measured: NsPerOp | MBPerS,
},
},
{
line: "BenchmarkEncrypt 100000000 19.6 ns/op 817.77",
want: &Benchmark{
Name: "BenchmarkEncrypt",
N: 100000000, NsPerOp: 19.6,
Measured: NsPerOp,
},
},
{
line: "BenchmarkEncrypt 100000000 19.6 ns/op 817.77 MB/s 5 allocs/op",
want: &Benchmark{
Name: "BenchmarkEncrypt",
N: 100000000, NsPerOp: 19.6, MBPerS: 817.77, AllocsPerOp: 5,
Measured: NsPerOp | MBPerS | AllocsPerOp,
},
},
{
line: "BenchmarkEncrypt 100000000 19.6 ns/op 817.77 MB/s 3 B/op 5 allocs/op",
want: &Benchmark{
Name: "BenchmarkEncrypt",
N: 100000000, NsPerOp: 19.6, MBPerS: 817.77, AllocedBytesPerOp: 3, AllocsPerOp: 5,
Measured: NsPerOp | MBPerS | AllocedBytesPerOp | AllocsPerOp,
},
},
// error handling cases
{
line: "BenchPress 100 19.6 ns/op", // non-benchmark
err: true,
},
{
line: "BenchmarkEncrypt lots 19.6 ns/op", // non-int iterations
err: true,
},
{
line: "BenchmarkBridge 100000000 19.6 smoots", // unknown unit
want: &Benchmark{
Name: "BenchmarkBridge",
N: 100000000,
},
},
{
line: "PASS",
err: true,
},
}
for _, tt := range cases {
have, err := ParseLine(tt.line)
if tt.err && err == nil {
t.Errorf("parsing line %q should have failed", tt.line)
continue
}
if !reflect.DeepEqual(have, tt.want) {
t.Errorf("parsed line %q incorrectly, want %v have %v", tt.line, tt.want, have)
}
}
}
func TestParseSet(t *testing.T) {
// Test two things:
// 1. The noise that can accompany testing.B output gets ignored.
// 2. Benchmarks with the same name have their order preserved.
in := `
? crypto [no test files]
PASS
pem_decrypt_test.go:17: test 4. %!s(x509.PEMCipher=5)
... [output truncated]
BenchmarkEncrypt 100000000 19.6 ns/op
BenchmarkEncrypt 5000000 517 ns/op
=== RUN TestChunk
--- PASS: TestChunk (0.00 seconds)
--- SKIP: TestLinuxSendfile (0.00 seconds)
fs_test.go:716: skipping; linux-only test
BenchmarkReadRequestApachebench 1000000 2960 ns/op 27.70 MB/s 839 B/op 9 allocs/op
BenchmarkClientServerParallel64 50000 59192 ns/op 7028 B/op 60 allocs/op
ok net/http 95.783s
`
want := Set{
"BenchmarkReadRequestApachebench": []*Benchmark{
{
Name: "BenchmarkReadRequestApachebench",
N: 1000000, NsPerOp: 2960, MBPerS: 27.70, AllocedBytesPerOp: 839, AllocsPerOp: 9,
Measured: NsPerOp | MBPerS | AllocedBytesPerOp | AllocsPerOp,
Ord: 2,
},
},
"BenchmarkClientServerParallel64": []*Benchmark{
{
Name: "BenchmarkClientServerParallel64",
N: 50000, NsPerOp: 59192, AllocedBytesPerOp: 7028, AllocsPerOp: 60,
Measured: NsPerOp | AllocedBytesPerOp | AllocsPerOp,
Ord: 3,
},
},
"BenchmarkEncrypt": []*Benchmark{
{
Name: "BenchmarkEncrypt",
N: 100000000, NsPerOp: 19.6,
Measured: NsPerOp,
Ord: 0,
},
{
Name: "BenchmarkEncrypt",
N: 5000000, NsPerOp: 517,
Measured: NsPerOp,
Ord: 1,
},
},
}
have, err := ParseSet(strings.NewReader(in))
if err != nil {
t.Fatalf("unexpected err during ParseSet: %v", err)
}
if !reflect.DeepEqual(want, have) {
t.Errorf("parsed bench set incorrectly, want %v have %v", want, have)
}
}

61
vendor/golang.org/x/tools/blog/atom/atom.go generated vendored Normal file
View File

@ -0,0 +1,61 @@
// 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.
// Adapted from encoding/xml/read_test.go.
// Package atom defines XML data structures for an Atom feed.
package atom // import "golang.org/x/tools/blog/atom"
import (
"encoding/xml"
"time"
)
type Feed struct {
XMLName xml.Name `xml:"http://www.w3.org/2005/Atom feed"`
Title string `xml:"title"`
ID string `xml:"id"`
Link []Link `xml:"link"`
Updated TimeStr `xml:"updated"`
Author *Person `xml:"author"`
Entry []*Entry `xml:"entry"`
}
type Entry struct {
Title string `xml:"title"`
ID string `xml:"id"`
Link []Link `xml:"link"`
Published TimeStr `xml:"published"`
Updated TimeStr `xml:"updated"`
Author *Person `xml:"author"`
Summary *Text `xml:"summary"`
Content *Text `xml:"content"`
}
type Link struct {
Rel string `xml:"rel,attr,omitempty"`
Href string `xml:"href,attr"`
Type string `xml:"type,attr,omitempty"`
HrefLang string `xml:"hreflang,attr,omitempty"`
Title string `xml:"title,attr,omitempty"`
Length uint `xml:"length,attr,omitempty"`
}
type Person struct {
Name string `xml:"name"`
URI string `xml:"uri,omitempty"`
Email string `xml:"email,omitempty"`
InnerXML string `xml:",innerxml"`
}
type Text struct {
Type string `xml:"type,attr"`
Body string `xml:",chardata"`
}
type TimeStr string
func Time(t time.Time) TimeStr {
return TimeStr(t.Format("2006-01-02T15:04:05-07:00"))
}

437
vendor/golang.org/x/tools/blog/blog.go generated vendored Normal file
View File

@ -0,0 +1,437 @@
// 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 blog implements a web server for articles written in present format.
package blog // import "golang.org/x/tools/blog"
import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"html/template"
"log"
"net/http"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"time"
"golang.org/x/tools/blog/atom"
"golang.org/x/tools/present"
)
var validJSONPFunc = regexp.MustCompile(`(?i)^[a-z_][a-z0-9_.]*$`)
// Config specifies Server configuration values.
type Config struct {
ContentPath string // Relative or absolute location of article files and related content.
TemplatePath string // Relative or absolute location of template files.
BaseURL string // Absolute base URL (for permalinks; no trailing slash).
BasePath string // Base URL path relative to server root (no trailing slash).
GodocURL string // The base URL of godoc (for menu bar; no trailing slash).
Hostname string // Server host name, used for rendering ATOM feeds.
HomeArticles int // Articles to display on the home page.
FeedArticles int // Articles to include in Atom and JSON feeds.
FeedTitle string // The title of the Atom XML feed
PlayEnabled bool
}
// Doc represents an article adorned with presentation data.
type Doc struct {
*present.Doc
Permalink string // Canonical URL for this document.
Path string // Path relative to server root (including base).
HTML template.HTML // rendered article
Related []*Doc
Newer, Older *Doc
}
// Server implements an http.Handler that serves blog articles.
type Server struct {
cfg Config
docs []*Doc
tags []string
docPaths map[string]*Doc // key is path without BasePath.
docTags map[string][]*Doc
template struct {
home, index, article, doc *template.Template
}
atomFeed []byte // pre-rendered Atom feed
jsonFeed []byte // pre-rendered JSON feed
content http.Handler
}
// NewServer constructs a new Server using the specified config.
func NewServer(cfg Config) (*Server, error) {
present.PlayEnabled = cfg.PlayEnabled
if notExist(cfg.TemplatePath) {
return nil, fmt.Errorf("template directory not found: %s", cfg.TemplatePath)
}
root := filepath.Join(cfg.TemplatePath, "root.tmpl")
parse := func(name string) (*template.Template, error) {
path := filepath.Join(cfg.TemplatePath, name)
if notExist(path) {
return nil, fmt.Errorf("template %s was not found in %s", name, cfg.TemplatePath)
}
t := template.New("").Funcs(funcMap)
return t.ParseFiles(root, path)
}
s := &Server{cfg: cfg}
// Parse templates.
var err error
s.template.home, err = parse("home.tmpl")
if err != nil {
return nil, err
}
s.template.index, err = parse("index.tmpl")
if err != nil {
return nil, err
}
s.template.article, err = parse("article.tmpl")
if err != nil {
return nil, err
}
p := present.Template().Funcs(funcMap)
s.template.doc, err = p.ParseFiles(filepath.Join(cfg.TemplatePath, "doc.tmpl"))
if err != nil {
return nil, err
}
// Load content.
err = s.loadDocs(filepath.Clean(cfg.ContentPath))
if err != nil {
return nil, err
}
err = s.renderAtomFeed()
if err != nil {
return nil, err
}
err = s.renderJSONFeed()
if err != nil {
return nil, err
}
// Set up content file server.
s.content = http.StripPrefix(s.cfg.BasePath, http.FileServer(http.Dir(cfg.ContentPath)))
return s, nil
}
var funcMap = template.FuncMap{
"sectioned": sectioned,
"authors": authors,
}
// sectioned returns true if the provided Doc contains more than one section.
// This is used to control whether to display the table of contents and headings.
func sectioned(d *present.Doc) bool {
return len(d.Sections) > 1
}
// authors returns a comma-separated list of author names.
func authors(authors []present.Author) string {
var b bytes.Buffer
last := len(authors) - 1
for i, a := range authors {
if i > 0 {
if i == last {
b.WriteString(" and ")
} else {
b.WriteString(", ")
}
}
b.WriteString(authorName(a))
}
return b.String()
}
// authorName returns the first line of the Author text: the author's name.
func authorName(a present.Author) string {
el := a.TextElem()
if len(el) == 0 {
return ""
}
text, ok := el[0].(present.Text)
if !ok || len(text.Lines) == 0 {
return ""
}
return text.Lines[0]
}
// loadDocs reads all content from the provided file system root, renders all
// the articles it finds, adds them to the Server's docs field, computes the
// denormalized docPaths, docTags, and tags fields, and populates the various
// helper fields (Next, Previous, Related) for each Doc.
func (s *Server) loadDocs(root string) error {
// Read content into docs field.
const ext = ".article"
fn := func(p string, info os.FileInfo, err error) error {
if filepath.Ext(p) != ext {
return nil
}
f, err := os.Open(p)
if err != nil {
return err
}
defer f.Close()
d, err := present.Parse(f, p, 0)
if err != nil {
return err
}
html := new(bytes.Buffer)
err = d.Render(html, s.template.doc)
if err != nil {
return err
}
p = p[len(root) : len(p)-len(ext)] // trim root and extension
p = filepath.ToSlash(p)
s.docs = append(s.docs, &Doc{
Doc: d,
Path: s.cfg.BasePath + p,
Permalink: s.cfg.BaseURL + p,
HTML: template.HTML(html.String()),
})
return nil
}
err := filepath.Walk(root, fn)
if err != nil {
return err
}
sort.Sort(docsByTime(s.docs))
// Pull out doc paths and tags and put in reverse-associating maps.
s.docPaths = make(map[string]*Doc)
s.docTags = make(map[string][]*Doc)
for _, d := range s.docs {
s.docPaths[strings.TrimPrefix(d.Path, s.cfg.BasePath)] = d
for _, t := range d.Tags {
s.docTags[t] = append(s.docTags[t], d)
}
}
// Pull out unique sorted list of tags.
for t := range s.docTags {
s.tags = append(s.tags, t)
}
sort.Strings(s.tags)
// Set up presentation-related fields, Newer, Older, and Related.
for _, doc := range s.docs {
// Newer, Older: docs adjacent to doc
for i := range s.docs {
if s.docs[i] != doc {
continue
}
if i > 0 {
doc.Newer = s.docs[i-1]
}
if i+1 < len(s.docs) {
doc.Older = s.docs[i+1]
}
break
}
// Related: all docs that share tags with doc.
related := make(map[*Doc]bool)
for _, t := range doc.Tags {
for _, d := range s.docTags[t] {
if d != doc {
related[d] = true
}
}
}
for d := range related {
doc.Related = append(doc.Related, d)
}
sort.Sort(docsByTime(doc.Related))
}
return nil
}
// renderAtomFeed generates an XML Atom feed and stores it in the Server's
// atomFeed field.
func (s *Server) renderAtomFeed() error {
var updated time.Time
if len(s.docs) > 0 {
updated = s.docs[0].Time
}
feed := atom.Feed{
Title: s.cfg.FeedTitle,
ID: "tag:" + s.cfg.Hostname + ",2013:" + s.cfg.Hostname,
Updated: atom.Time(updated),
Link: []atom.Link{{
Rel: "self",
Href: s.cfg.BaseURL + "/feed.atom",
}},
}
for i, doc := range s.docs {
if i >= s.cfg.FeedArticles {
break
}
e := &atom.Entry{
Title: doc.Title,
ID: feed.ID + doc.Path,
Link: []atom.Link{{
Rel: "alternate",
Href: doc.Permalink,
}},
Published: atom.Time(doc.Time),
Updated: atom.Time(doc.Time),
Summary: &atom.Text{
Type: "html",
Body: summary(doc),
},
Content: &atom.Text{
Type: "html",
Body: string(doc.HTML),
},
Author: &atom.Person{
Name: authors(doc.Authors),
},
}
feed.Entry = append(feed.Entry, e)
}
data, err := xml.Marshal(&feed)
if err != nil {
return err
}
s.atomFeed = data
return nil
}
type jsonItem struct {
Title string
Link string
Time time.Time
Summary string
Content string
Author string
}
// renderJSONFeed generates a JSON feed and stores it in the Server's jsonFeed
// field.
func (s *Server) renderJSONFeed() error {
var feed []jsonItem
for i, doc := range s.docs {
if i >= s.cfg.FeedArticles {
break
}
item := jsonItem{
Title: doc.Title,
Link: doc.Permalink,
Time: doc.Time,
Summary: summary(doc),
Content: string(doc.HTML),
Author: authors(doc.Authors),
}
feed = append(feed, item)
}
data, err := json.Marshal(feed)
if err != nil {
return err
}
s.jsonFeed = data
return nil
}
// summary returns the first paragraph of text from the provided Doc.
func summary(d *Doc) string {
if len(d.Sections) == 0 {
return ""
}
for _, elem := range d.Sections[0].Elem {
text, ok := elem.(present.Text)
if !ok || text.Pre {
// skip everything but non-text elements
continue
}
var buf bytes.Buffer
for _, s := range text.Lines {
buf.WriteString(string(present.Style(s)))
buf.WriteByte('\n')
}
return buf.String()
}
return ""
}
// rootData encapsulates data destined for the root template.
type rootData struct {
Doc *Doc
BasePath string
GodocURL string
Data interface{}
}
// ServeHTTP serves the front, index, and article pages
// as well as the ATOM and JSON feeds.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var (
d = rootData{BasePath: s.cfg.BasePath, GodocURL: s.cfg.GodocURL}
t *template.Template
)
switch p := strings.TrimPrefix(r.URL.Path, s.cfg.BasePath); p {
case "/":
d.Data = s.docs
if len(s.docs) > s.cfg.HomeArticles {
d.Data = s.docs[:s.cfg.HomeArticles]
}
t = s.template.home
case "/index":
d.Data = s.docs
t = s.template.index
case "/feed.atom", "/feeds/posts/default":
w.Header().Set("Content-type", "application/atom+xml; charset=utf-8")
w.Write(s.atomFeed)
return
case "/.json":
if p := r.FormValue("jsonp"); validJSONPFunc.MatchString(p) {
w.Header().Set("Content-type", "application/javascript; charset=utf-8")
fmt.Fprintf(w, "%v(%s)", p, s.jsonFeed)
return
}
w.Header().Set("Content-type", "application/json; charset=utf-8")
w.Write(s.jsonFeed)
return
default:
doc, ok := s.docPaths[p]
if !ok {
// Not a doc; try to just serve static content.
s.content.ServeHTTP(w, r)
return
}
d.Doc = doc
t = s.template.article
}
err := t.ExecuteTemplate(w, "root", d)
if err != nil {
log.Println(err)
}
}
// docsByTime implements sort.Interface, sorting Docs by their Time field.
type docsByTime []*Doc
func (s docsByTime) Len() int { return len(s) }
func (s docsByTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s docsByTime) Less(i, j int) bool { return s[i].Time.After(s[j].Time) }
// notExist reports whether the path exists or not.
func notExist(path string) bool {
_, err := os.Stat(path)
return os.IsNotExist(err)
}

184
vendor/golang.org/x/tools/cmd/benchcmp/benchcmp.go generated vendored Normal file
View File

@ -0,0 +1,184 @@
// 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.
package main
import (
"flag"
"fmt"
"os"
"sort"
"strconv"
"text/tabwriter"
"golang.org/x/tools/benchmark/parse"
)
var (
changedOnly = flag.Bool("changed", false, "show only benchmarks that have changed")
magSort = flag.Bool("mag", false, "sort benchmarks by magnitude of change")
best = flag.Bool("best", false, "compare best times from old and new")
)
const usageFooter = `
Each input file should be from:
go test -run=NONE -bench=. > [old,new].txt
Benchcmp compares old and new for each benchmark.
If -test.benchmem=true is added to the "go test" command
benchcmp will also compare memory allocations.
`
func main() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "usage: %s old.txt new.txt\n\n", os.Args[0])
flag.PrintDefaults()
fmt.Fprint(os.Stderr, usageFooter)
os.Exit(2)
}
flag.Parse()
if flag.NArg() != 2 {
flag.Usage()
}
before := parseFile(flag.Arg(0))
after := parseFile(flag.Arg(1))
cmps, warnings := Correlate(before, after)
for _, warn := range warnings {
fmt.Fprintln(os.Stderr, warn)
}
if len(cmps) == 0 {
fatal("benchcmp: no repeated benchmarks")
}
w := new(tabwriter.Writer)
w.Init(os.Stdout, 0, 0, 5, ' ', 0)
defer w.Flush()
var header bool // Has the header has been displayed yet for a given block?
if *magSort {
sort.Sort(ByDeltaNsPerOp(cmps))
} else {
sort.Sort(ByParseOrder(cmps))
}
for _, cmp := range cmps {
if !cmp.Measured(parse.NsPerOp) {
continue
}
if delta := cmp.DeltaNsPerOp(); !*changedOnly || delta.Changed() {
if !header {
fmt.Fprint(w, "benchmark\told ns/op\tnew ns/op\tdelta\n")
header = true
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", cmp.Name(), formatNs(cmp.Before.NsPerOp), formatNs(cmp.After.NsPerOp), delta.Percent())
}
}
header = false
if *magSort {
sort.Sort(ByDeltaMBPerS(cmps))
}
for _, cmp := range cmps {
if !cmp.Measured(parse.MBPerS) {
continue
}
if delta := cmp.DeltaMBPerS(); !*changedOnly || delta.Changed() {
if !header {
fmt.Fprint(w, "\nbenchmark\told MB/s\tnew MB/s\tspeedup\n")
header = true
}
fmt.Fprintf(w, "%s\t%.2f\t%.2f\t%s\n", cmp.Name(), cmp.Before.MBPerS, cmp.After.MBPerS, delta.Multiple())
}
}
header = false
if *magSort {
sort.Sort(ByDeltaAllocsPerOp(cmps))
}
for _, cmp := range cmps {
if !cmp.Measured(parse.AllocsPerOp) {
continue
}
if delta := cmp.DeltaAllocsPerOp(); !*changedOnly || delta.Changed() {
if !header {
fmt.Fprint(w, "\nbenchmark\told allocs\tnew allocs\tdelta\n")
header = true
}
fmt.Fprintf(w, "%s\t%d\t%d\t%s\n", cmp.Name(), cmp.Before.AllocsPerOp, cmp.After.AllocsPerOp, delta.Percent())
}
}
header = false
if *magSort {
sort.Sort(ByDeltaAllocedBytesPerOp(cmps))
}
for _, cmp := range cmps {
if !cmp.Measured(parse.AllocedBytesPerOp) {
continue
}
if delta := cmp.DeltaAllocedBytesPerOp(); !*changedOnly || delta.Changed() {
if !header {
fmt.Fprint(w, "\nbenchmark\told bytes\tnew bytes\tdelta\n")
header = true
}
fmt.Fprintf(w, "%s\t%d\t%d\t%s\n", cmp.Name(), cmp.Before.AllocedBytesPerOp, cmp.After.AllocedBytesPerOp, cmp.DeltaAllocedBytesPerOp().Percent())
}
}
}
func fatal(msg interface{}) {
fmt.Fprintln(os.Stderr, msg)
os.Exit(1)
}
func parseFile(path string) parse.Set {
f, err := os.Open(path)
if err != nil {
fatal(err)
}
defer f.Close()
bb, err := parse.ParseSet(f)
if err != nil {
fatal(err)
}
if *best {
selectBest(bb)
}
return bb
}
func selectBest(bs parse.Set) {
for name, bb := range bs {
if len(bb) < 2 {
continue
}
ord := bb[0].Ord
best := bb[0]
for _, b := range bb {
if b.NsPerOp < best.NsPerOp {
b.Ord = ord
best = b
}
}
bs[name] = []*parse.Benchmark{best}
}
}
// formatNs formats ns measurements to expose a useful amount of
// precision. It mirrors the ns precision logic of testing.B.
func formatNs(ns float64) string {
prec := 0
switch {
case ns < 10:
prec = 2
case ns < 100:
prec = 1
}
return strconv.FormatFloat(ns, 'f', prec, 64)
}

View File

@ -0,0 +1,59 @@
package main
import (
"reflect"
"testing"
"golang.org/x/tools/benchmark/parse"
)
func TestSelectBest(t *testing.T) {
have := parse.Set{
"Benchmark1": []*parse.Benchmark{
{
Name: "Benchmark1",
N: 10, NsPerOp: 100, Measured: parse.NsPerOp,
Ord: 0,
},
{
Name: "Benchmark1",
N: 10, NsPerOp: 50, Measured: parse.NsPerOp,
Ord: 3,
},
},
"Benchmark2": []*parse.Benchmark{
{
Name: "Benchmark2",
N: 10, NsPerOp: 60, Measured: parse.NsPerOp,
Ord: 1,
},
{
Name: "Benchmark2",
N: 10, NsPerOp: 500, Measured: parse.NsPerOp,
Ord: 2,
},
},
}
want := parse.Set{
"Benchmark1": []*parse.Benchmark{
{
Name: "Benchmark1",
N: 10, NsPerOp: 50, Measured: parse.NsPerOp,
Ord: 0,
},
},
"Benchmark2": []*parse.Benchmark{
{
Name: "Benchmark2",
N: 10, NsPerOp: 60, Measured: parse.NsPerOp,
Ord: 1,
},
},
}
selectBest(have)
if !reflect.DeepEqual(want, have) {
t.Errorf("filtered bench set incorrectly, want %v have %v", want, have)
}
}

156
vendor/golang.org/x/tools/cmd/benchcmp/compare.go generated vendored Normal file
View File

@ -0,0 +1,156 @@
// 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.
package main
import (
"fmt"
"math"
"golang.org/x/tools/benchmark/parse"
)
// BenchCmp is a pair of benchmarks.
type BenchCmp struct {
Before *parse.Benchmark
After *parse.Benchmark
}
// Correlate correlates benchmarks from two BenchSets.
func Correlate(before, after parse.Set) (cmps []BenchCmp, warnings []string) {
cmps = make([]BenchCmp, 0, len(after))
for name, beforebb := range before {
afterbb := after[name]
if len(beforebb) != len(afterbb) {
warnings = append(warnings, fmt.Sprintf("ignoring %s: before has %d instances, after has %d", name, len(beforebb), len(afterbb)))
continue
}
for i, beforeb := range beforebb {
afterb := afterbb[i]
cmps = append(cmps, BenchCmp{beforeb, afterb})
}
}
return
}
func (c BenchCmp) Name() string { return c.Before.Name }
func (c BenchCmp) String() string { return fmt.Sprintf("<%s, %s>", c.Before, c.After) }
func (c BenchCmp) Measured(flag int) bool { return (c.Before.Measured & c.After.Measured & flag) != 0 }
func (c BenchCmp) DeltaNsPerOp() Delta { return Delta{c.Before.NsPerOp, c.After.NsPerOp} }
func (c BenchCmp) DeltaMBPerS() Delta { return Delta{c.Before.MBPerS, c.After.MBPerS} }
func (c BenchCmp) DeltaAllocedBytesPerOp() Delta {
return Delta{float64(c.Before.AllocedBytesPerOp), float64(c.After.AllocedBytesPerOp)}
}
func (c BenchCmp) DeltaAllocsPerOp() Delta {
return Delta{float64(c.Before.AllocsPerOp), float64(c.After.AllocsPerOp)}
}
// Delta is the before and after value for a benchmark measurement.
// Both must be non-negative.
type Delta struct {
Before float64
After float64
}
// mag calculates the magnitude of a change, regardless of the direction of
// the change. mag is intended for sorting and has no independent meaning.
func (d Delta) mag() float64 {
switch {
case d.Before != 0 && d.After != 0 && d.Before >= d.After:
return d.After / d.Before
case d.Before != 0 && d.After != 0 && d.Before < d.After:
return d.Before / d.After
case d.Before == 0 && d.After == 0:
return 1
default:
// 0 -> 1 or 1 -> 0
// These are significant changes and worth surfacing.
return math.Inf(1)
}
}
// Changed reports whether the benchmark quantities are different.
func (d Delta) Changed() bool { return d.Before != d.After }
// Float64 returns After / Before. If Before is 0, Float64 returns
// 1 if After is also 0, and +Inf otherwise.
func (d Delta) Float64() float64 {
switch {
case d.Before != 0:
return d.After / d.Before
case d.After == 0:
return 1
default:
return math.Inf(1)
}
}
// Percent formats a Delta as a percent change, ranging from -100% up.
func (d Delta) Percent() string {
return fmt.Sprintf("%+.2f%%", 100*d.Float64()-100)
}
// Multiple formats a Delta as a multiplier, ranging from 0.00x up.
func (d Delta) Multiple() string {
return fmt.Sprintf("%.2fx", d.Float64())
}
func (d Delta) String() string {
return fmt.Sprintf("Δ(%f, %f)", d.Before, d.After)
}
// ByParseOrder sorts BenchCmps to match the order in
// which the Before benchmarks were presented to Parse.
type ByParseOrder []BenchCmp
func (x ByParseOrder) Len() int { return len(x) }
func (x ByParseOrder) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x ByParseOrder) Less(i, j int) bool { return x[i].Before.Ord < x[j].Before.Ord }
// lessByDelta provides lexicographic ordering:
// * largest delta by magnitude
// * alphabetic by name
func lessByDelta(i, j BenchCmp, calcDelta func(BenchCmp) Delta) bool {
iDelta, jDelta := calcDelta(i).mag(), calcDelta(j).mag()
if iDelta != jDelta {
return iDelta < jDelta
}
return i.Name() < j.Name()
}
// ByDeltaNsPerOp sorts BenchCmps lexicographically by change
// in ns/op, descending, then by benchmark name.
type ByDeltaNsPerOp []BenchCmp
func (x ByDeltaNsPerOp) Len() int { return len(x) }
func (x ByDeltaNsPerOp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x ByDeltaNsPerOp) Less(i, j int) bool { return lessByDelta(x[i], x[j], BenchCmp.DeltaNsPerOp) }
// ByDeltaMBPerS sorts BenchCmps lexicographically by change
// in MB/s, descending, then by benchmark name.
type ByDeltaMBPerS []BenchCmp
func (x ByDeltaMBPerS) Len() int { return len(x) }
func (x ByDeltaMBPerS) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x ByDeltaMBPerS) Less(i, j int) bool { return lessByDelta(x[i], x[j], BenchCmp.DeltaMBPerS) }
// ByDeltaAllocedBytesPerOp sorts BenchCmps lexicographically by change
// in B/op, descending, then by benchmark name.
type ByDeltaAllocedBytesPerOp []BenchCmp
func (x ByDeltaAllocedBytesPerOp) Len() int { return len(x) }
func (x ByDeltaAllocedBytesPerOp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x ByDeltaAllocedBytesPerOp) Less(i, j int) bool {
return lessByDelta(x[i], x[j], BenchCmp.DeltaAllocedBytesPerOp)
}
// ByDeltaAllocsPerOp sorts BenchCmps lexicographically by change
// in allocs/op, descending, then by benchmark name.
type ByDeltaAllocsPerOp []BenchCmp
func (x ByDeltaAllocsPerOp) Len() int { return len(x) }
func (x ByDeltaAllocsPerOp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x ByDeltaAllocsPerOp) Less(i, j int) bool {
return lessByDelta(x[i], x[j], BenchCmp.DeltaAllocsPerOp)
}

133
vendor/golang.org/x/tools/cmd/benchcmp/compare_test.go generated vendored Normal file
View File

@ -0,0 +1,133 @@
// 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.
package main
import (
"math"
"reflect"
"sort"
"testing"
"golang.org/x/tools/benchmark/parse"
)
func TestDelta(t *testing.T) {
cases := []struct {
before float64
after float64
mag float64
f float64
changed bool
pct string
mult string
}{
{before: 1, after: 1, mag: 1, f: 1, changed: false, pct: "+0.00%", mult: "1.00x"},
{before: 1, after: 2, mag: 0.5, f: 2, changed: true, pct: "+100.00%", mult: "2.00x"},
{before: 2, after: 1, mag: 0.5, f: 0.5, changed: true, pct: "-50.00%", mult: "0.50x"},
{before: 0, after: 0, mag: 1, f: 1, changed: false, pct: "+0.00%", mult: "1.00x"},
{before: 1, after: 0, mag: math.Inf(1), f: 0, changed: true, pct: "-100.00%", mult: "0.00x"},
{before: 0, after: 1, mag: math.Inf(1), f: math.Inf(1), changed: true, pct: "+Inf%", mult: "+Infx"},
}
for _, tt := range cases {
d := Delta{tt.before, tt.after}
if want, have := tt.mag, d.mag(); want != have {
t.Errorf("%s.mag(): want %f have %f", d, want, have)
}
if want, have := tt.f, d.Float64(); want != have {
t.Errorf("%s.Float64(): want %f have %f", d, want, have)
}
if want, have := tt.changed, d.Changed(); want != have {
t.Errorf("%s.Changed(): want %t have %t", d, want, have)
}
if want, have := tt.pct, d.Percent(); want != have {
t.Errorf("%s.Percent(): want %q have %q", d, want, have)
}
if want, have := tt.mult, d.Multiple(); want != have {
t.Errorf("%s.Multiple(): want %q have %q", d, want, have)
}
}
}
func TestCorrelate(t *testing.T) {
// Benches that are going to be successfully correlated get N thus:
// 0x<counter><num benches><b = before | a = after>
// Read this: "<counter> of <num benches>, from <before|after>".
before := parse.Set{
"BenchmarkOneEach": []*parse.Benchmark{{Name: "BenchmarkOneEach", N: 0x11b}},
"BenchmarkOneToNone": []*parse.Benchmark{{Name: "BenchmarkOneToNone"}},
"BenchmarkOneToTwo": []*parse.Benchmark{{Name: "BenchmarkOneToTwo"}},
"BenchmarkTwoToOne": []*parse.Benchmark{
{Name: "BenchmarkTwoToOne"},
{Name: "BenchmarkTwoToOne"},
},
"BenchmarkTwoEach": []*parse.Benchmark{
{Name: "BenchmarkTwoEach", N: 0x12b},
{Name: "BenchmarkTwoEach", N: 0x22b},
},
}
after := parse.Set{
"BenchmarkOneEach": []*parse.Benchmark{{Name: "BenchmarkOneEach", N: 0x11a}},
"BenchmarkNoneToOne": []*parse.Benchmark{{Name: "BenchmarkNoneToOne"}},
"BenchmarkTwoToOne": []*parse.Benchmark{{Name: "BenchmarkTwoToOne"}},
"BenchmarkOneToTwo": []*parse.Benchmark{
{Name: "BenchmarkOneToTwo"},
{Name: "BenchmarkOneToTwo"},
},
"BenchmarkTwoEach": []*parse.Benchmark{
{Name: "BenchmarkTwoEach", N: 0x12a},
{Name: "BenchmarkTwoEach", N: 0x22a},
},
}
pairs, errs := Correlate(before, after)
// Fail to match: BenchmarkOneToNone, BenchmarkOneToTwo, BenchmarkTwoToOne.
// Correlate does not notice BenchmarkNoneToOne.
if len(errs) != 3 {
t.Errorf("Correlated expected 4 errors, got %d: %v", len(errs), errs)
}
// Want three correlated pairs: one BenchmarkOneEach, two BenchmarkTwoEach.
if len(pairs) != 3 {
t.Fatalf("Correlated expected 3 pairs, got %v", pairs)
}
for _, pair := range pairs {
if pair.Before.N&0xF != 0xb {
t.Errorf("unexpected Before in pair %s", pair)
}
if pair.After.N&0xF != 0xa {
t.Errorf("unexpected After in pair %s", pair)
}
if pair.Before.N>>4 != pair.After.N>>4 {
t.Errorf("mismatched pair %s", pair)
}
}
}
func TestBenchCmpSorting(t *testing.T) {
c := []BenchCmp{
{&parse.Benchmark{Name: "BenchmarkMuchFaster", NsPerOp: 10, Ord: 3}, &parse.Benchmark{Name: "BenchmarkMuchFaster", NsPerOp: 1}},
{&parse.Benchmark{Name: "BenchmarkSameB", NsPerOp: 5, Ord: 1}, &parse.Benchmark{Name: "BenchmarkSameB", NsPerOp: 5}},
{&parse.Benchmark{Name: "BenchmarkSameA", NsPerOp: 5, Ord: 2}, &parse.Benchmark{Name: "BenchmarkSameA", NsPerOp: 5}},
{&parse.Benchmark{Name: "BenchmarkSlower", NsPerOp: 10, Ord: 0}, &parse.Benchmark{Name: "BenchmarkSlower", NsPerOp: 11}},
}
// Test just one magnitude-based sort order; they are symmetric.
sort.Sort(ByDeltaNsPerOp(c))
want := []string{"BenchmarkMuchFaster", "BenchmarkSlower", "BenchmarkSameA", "BenchmarkSameB"}
have := []string{c[0].Name(), c[1].Name(), c[2].Name(), c[3].Name()}
if !reflect.DeepEqual(want, have) {
t.Errorf("ByDeltaNsOp incorrect sorting: want %v have %v", want, have)
}
sort.Sort(ByParseOrder(c))
want = []string{"BenchmarkSlower", "BenchmarkSameB", "BenchmarkSameA", "BenchmarkMuchFaster"}
have = []string{c[0].Name(), c[1].Name(), c[2].Name(), c[3].Name()}
if !reflect.DeepEqual(want, have) {
t.Errorf("ByParseOrder incorrect sorting: want %v have %v", want, have)
}
}

37
vendor/golang.org/x/tools/cmd/benchcmp/doc.go generated vendored Normal file
View File

@ -0,0 +1,37 @@
// 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.
/*
The benchcmp command displays performance changes between benchmarks.
Benchcmp parses the output of two 'go test' benchmark runs,
correlates the results per benchmark, and displays the deltas.
To measure the performance impact of a change, use 'go test'
to run benchmarks before and after the change:
go test -run=NONE -bench=. ./... > old.txt
# make changes
go test -run=NONE -bench=. ./... > new.txt
Then feed the benchmark results to benchcmp:
benchcmp old.txt new.txt
Benchcmp will summarize and display the performance changes,
in a format like this:
$ benchcmp old.txt new.txt
benchmark old ns/op new ns/op delta
BenchmarkConcat 523 68.6 -86.88%
benchmark old allocs new allocs delta
BenchmarkConcat 3 1 -66.67%
benchmark old bytes new bytes delta
BenchmarkConcat 80 48 -40.00%
*/
package main // import "golang.org/x/tools/cmd/benchcmp"

1
vendor/golang.org/x/tools/cmd/bundle/.gitignore generated vendored Normal file
View File

@ -0,0 +1 @@
testdata/out.got

468
vendor/golang.org/x/tools/cmd/bundle/main.go generated vendored Normal file
View File

@ -0,0 +1,468 @@
// 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.
// Bundle creates a single-source-file version of a source package
// suitable for inclusion in a particular target package.
//
// Usage:
//
// bundle [-o file] [-dst path] [-pkg name] [-prefix p] [-import old=new] <src>
//
// The src argument specifies the import path of the package to bundle.
// The bundling of a directory of source files into a single source file
// necessarily imposes a number of constraints.
// The package being bundled must not use cgo; must not use conditional
// file compilation, whether with build tags or system-specific file names
// like code_amd64.go; must not depend on any special comments, which
// may not be preserved; must not use any assembly sources;
// must not use renaming imports; and must not use reflection-based APIs
// that depend on the specific names of types or struct fields.
//
// By default, bundle writes the bundled code to standard output.
// If the -o argument is given, bundle writes to the named file
// and also includes a ``//go:generate'' comment giving the exact
// command line used, for regenerating the file with ``go generate.''
//
// Bundle customizes its output for inclusion in a particular package, the destination package.
// By default bundle assumes the destination is the package in the current directory,
// but the destination package can be specified explicitly using the -dst option,
// which takes an import path as its argument.
// If the source package imports the destination package, bundle will remove
// those imports and rewrite any references to use direct references to the
// corresponding symbols.
// Bundle also must write a package declaration in the output and must
// choose a name to use in that declaration.
// If the -package option is given, bundle uses that name.
// Otherwise, if the -dst option is given, bundle uses the last
// element of the destination import path.
// Otherwise, by default bundle uses the package name found in the
// package sources in the current directory.
//
// To avoid collisions, bundle inserts a prefix at the beginning of
// every package-level const, func, type, and var identifier in src's code,
// updating references accordingly. The default prefix is the package name
// of the source package followed by an underscore. The -prefix option
// specifies an alternate prefix.
//
// Occasionally it is necessary to rewrite imports during the bundling
// process. The -import option, which may be repeated, specifies that
// an import of "old" should be rewritten to import "new" instead.
//
// Example
//
// Bundle archive/zip for inclusion in cmd/dist:
//
// cd $GOROOT/src/cmd/dist
// bundle -o zip.go archive/zip
//
// Bundle golang.org/x/net/http2 for inclusion in net/http,
// prefixing all identifiers by "http2" instead of "http2_",
// and rewriting the import "golang.org/x/net/http2/hpack"
// to "internal/golang.org/x/net/http2/hpack":
//
// cd $GOROOT/src/net/http
// bundle -o h2_bundle.go \
// -prefix http2 \
// -import golang.org/x/net/http2/hpack=internal/golang.org/x/net/http2/hpack \
// golang.org/x/net/http2
//
// Two ways to update the http2 bundle:
//
// go generate net/http
//
// cd $GOROOT/src/net/http
// go generate
//
// Update both bundles, restricting ``go generate'' to running bundle commands:
//
// go generate -run bundle cmd/dist net/http
//
package main
import (
"bytes"
"flag"
"fmt"
"go/ast"
"go/build"
"go/format"
"go/parser"
"go/printer"
"go/token"
"go/types"
"io/ioutil"
"log"
"os"
"path"
"strconv"
"strings"
"golang.org/x/tools/go/loader"
)
var (
outputFile = flag.String("o", "", "write output to `file` (default standard output)")
dstPath = flag.String("dst", "", "set destination import `path` (default taken from current directory)")
pkgName = flag.String("pkg", "", "set destination package `name` (default taken from current directory)")
prefix = flag.String("prefix", "", "set bundled identifier prefix to `p` (default source package name + \"_\")")
underscore = flag.Bool("underscore", false, "rewrite golang.org to golang_org in imports; temporary workaround for golang.org/issue/16333")
importMap = map[string]string{}
)
func init() {
flag.Var(flagFunc(addImportMap), "import", "rewrite import using `map`, of form old=new (can be repeated)")
}
func addImportMap(s string) {
if strings.Count(s, "=") != 1 {
log.Fatal("-import argument must be of the form old=new")
}
i := strings.Index(s, "=")
old, new := s[:i], s[i+1:]
if old == "" || new == "" {
log.Fatal("-import argument must be of the form old=new; old and new must be non-empty")
}
importMap[old] = new
}
func usage() {
fmt.Fprintf(os.Stderr, "Usage: bundle [options] <src>\n")
flag.PrintDefaults()
}
func main() {
log.SetPrefix("bundle: ")
log.SetFlags(0)
flag.Usage = usage
flag.Parse()
args := flag.Args()
if len(args) != 1 {
usage()
os.Exit(2)
}
if *dstPath != "" {
if *pkgName == "" {
*pkgName = path.Base(*dstPath)
}
} else {
wd, _ := os.Getwd()
pkg, err := build.ImportDir(wd, 0)
if err != nil {
log.Fatalf("cannot find package in current directory: %v", err)
}
*dstPath = pkg.ImportPath
if *pkgName == "" {
*pkgName = pkg.Name
}
}
code, err := bundle(args[0], *dstPath, *pkgName, *prefix)
if err != nil {
log.Fatal(err)
}
if *outputFile != "" {
err := ioutil.WriteFile(*outputFile, code, 0666)
if err != nil {
log.Fatal(err)
}
} else {
_, err := os.Stdout.Write(code)
if err != nil {
log.Fatal(err)
}
}
}
// isStandardImportPath is copied from cmd/go in the standard library.
func isStandardImportPath(path string) bool {
i := strings.Index(path, "/")
if i < 0 {
i = len(path)
}
elem := path[:i]
return !strings.Contains(elem, ".")
}
var ctxt = &build.Default
func bundle(src, dst, dstpkg, prefix string) ([]byte, error) {
// Load the initial package.
conf := loader.Config{ParserMode: parser.ParseComments, Build: ctxt}
conf.TypeCheckFuncBodies = func(p string) bool { return p == src }
conf.Import(src)
lprog, err := conf.Load()
if err != nil {
return nil, err
}
// Because there was a single Import call and Load succeeded,
// InitialPackages is guaranteed to hold the sole requested package.
info := lprog.InitialPackages()[0]
if prefix == "" {
pkgName := info.Files[0].Name.Name
prefix = pkgName + "_"
}
objsToUpdate := make(map[types.Object]bool)
var rename func(from types.Object)
rename = func(from types.Object) {
if !objsToUpdate[from] {
objsToUpdate[from] = true
// Renaming a type that is used as an embedded field
// requires renaming the field too. e.g.
// type T int // if we rename this to U..
// var s struct {T}
// print(s.T) // ...this must change too
if _, ok := from.(*types.TypeName); ok {
for id, obj := range info.Uses {
if obj == from {
if field := info.Defs[id]; field != nil {
rename(field)
}
}
}
}
}
}
// Rename each package-level object.
scope := info.Pkg.Scope()
for _, name := range scope.Names() {
rename(scope.Lookup(name))
}
var out bytes.Buffer
fmt.Fprintf(&out, "// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.\n")
if *outputFile != "" {
fmt.Fprintf(&out, "//go:generate bundle %s\n", strings.Join(os.Args[1:], " "))
} else {
fmt.Fprintf(&out, "// $ bundle %s\n", strings.Join(os.Args[1:], " "))
}
fmt.Fprintf(&out, "\n")
// Concatenate package comments from all files...
for _, f := range info.Files {
if doc := f.Doc.Text(); strings.TrimSpace(doc) != "" {
for _, line := range strings.Split(doc, "\n") {
fmt.Fprintf(&out, "// %s\n", line)
}
}
}
// ...but don't let them become the actual package comment.
fmt.Fprintln(&out)
fmt.Fprintf(&out, "package %s\n\n", dstpkg)
// BUG(adonovan,shurcooL): bundle may generate incorrect code
// due to shadowing between identifiers and imported package names.
//
// The generated code will either fail to compile or
// (unlikely) compile successfully but have different behavior
// than the original package. The risk of this happening is higher
// when the original package has renamed imports (they're typically
// renamed in order to resolve a shadow inside that particular .go file).
// TODO(adonovan,shurcooL):
// - detect shadowing issues, and either return error or resolve them
// - preserve comments from the original import declarations.
// pkgStd and pkgExt are sets of printed import specs. This is done
// to deduplicate instances of the same import name and path.
var pkgStd = make(map[string]bool)
var pkgExt = make(map[string]bool)
for _, f := range info.Files {
for _, imp := range f.Imports {
path, err := strconv.Unquote(imp.Path.Value)
if err != nil {
log.Fatalf("invalid import path string: %v", err) // Shouldn't happen here since conf.Load succeeded.
}
if path == dst {
continue
}
if newPath, ok := importMap[path]; ok {
path = newPath
}
var name string
if imp.Name != nil {
name = imp.Name.Name
}
spec := fmt.Sprintf("%s %q", name, path)
if isStandardImportPath(path) {
pkgStd[spec] = true
} else {
if *underscore {
spec = strings.Replace(spec, "golang.org/", "golang_org/", 1)
}
pkgExt[spec] = true
}
}
}
// Print a single declaration that imports all necessary packages.
fmt.Fprintln(&out, "import (")
for p := range pkgStd {
fmt.Fprintf(&out, "\t%s\n", p)
}
if len(pkgExt) > 0 {
fmt.Fprintln(&out)
}
for p := range pkgExt {
fmt.Fprintf(&out, "\t%s\n", p)
}
fmt.Fprint(&out, ")\n\n")
// Modify and print each file.
for _, f := range info.Files {
// Update renamed identifiers.
for id, obj := range info.Defs {
if objsToUpdate[obj] {
id.Name = prefix + obj.Name()
}
}
for id, obj := range info.Uses {
if objsToUpdate[obj] {
id.Name = prefix + obj.Name()
}
}
// For each qualified identifier that refers to the
// destination package, remove the qualifier.
// The "@@@." strings are removed in postprocessing.
ast.Inspect(f, func(n ast.Node) bool {
if sel, ok := n.(*ast.SelectorExpr); ok {
if id, ok := sel.X.(*ast.Ident); ok {
if obj, ok := info.Uses[id].(*types.PkgName); ok {
if obj.Imported().Path() == dst {
id.Name = "@@@"
}
}
}
}
return true
})
last := f.Package
if len(f.Imports) > 0 {
imp := f.Imports[len(f.Imports)-1]
last = imp.End()
if imp.Comment != nil {
if e := imp.Comment.End(); e > last {
last = e
}
}
}
// Pretty-print package-level declarations.
// but no package or import declarations.
var buf bytes.Buffer
for _, decl := range f.Decls {
if decl, ok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT {
continue
}
beg, end := sourceRange(decl)
printComments(&out, f.Comments, last, beg)
buf.Reset()
format.Node(&buf, lprog.Fset, &printer.CommentedNode{Node: decl, Comments: f.Comments})
// Remove each "@@@." in the output.
// TODO(adonovan): not hygienic.
out.Write(bytes.Replace(buf.Bytes(), []byte("@@@."), nil, -1))
last = printSameLineComment(&out, f.Comments, lprog.Fset, end)
out.WriteString("\n\n")
}
printLastComments(&out, f.Comments, last)
}
// Now format the entire thing.
result, err := format.Source(out.Bytes())
if err != nil {
log.Fatalf("formatting failed: %v", err)
}
return result, nil
}
// sourceRange returns the [beg, end) interval of source code
// belonging to decl (incl. associated comments).
func sourceRange(decl ast.Decl) (beg, end token.Pos) {
beg = decl.Pos()
end = decl.End()
var doc, com *ast.CommentGroup
switch d := decl.(type) {
case *ast.GenDecl:
doc = d.Doc
if len(d.Specs) > 0 {
switch spec := d.Specs[len(d.Specs)-1].(type) {
case *ast.ValueSpec:
com = spec.Comment
case *ast.TypeSpec:
com = spec.Comment
}
}
case *ast.FuncDecl:
doc = d.Doc
}
if doc != nil {
beg = doc.Pos()
}
if com != nil && com.End() > end {
end = com.End()
}
return beg, end
}
func printComments(out *bytes.Buffer, comments []*ast.CommentGroup, pos, end token.Pos) {
for _, cg := range comments {
if pos <= cg.Pos() && cg.Pos() < end {
for _, c := range cg.List {
fmt.Fprintln(out, c.Text)
}
fmt.Fprintln(out)
}
}
}
const infinity = 1 << 30
func printLastComments(out *bytes.Buffer, comments []*ast.CommentGroup, pos token.Pos) {
printComments(out, comments, pos, infinity)
}
func printSameLineComment(out *bytes.Buffer, comments []*ast.CommentGroup, fset *token.FileSet, pos token.Pos) token.Pos {
tf := fset.File(pos)
for _, cg := range comments {
if pos <= cg.Pos() && tf.Line(cg.Pos()) == tf.Line(pos) {
for _, c := range cg.List {
fmt.Fprintln(out, c.Text)
}
return cg.End()
}
}
return pos
}
type flagFunc func(string)
func (f flagFunc) Set(s string) error {
f(s)
return nil
}
func (f flagFunc) String() string { return "" }

74
vendor/golang.org/x/tools/cmd/bundle/main_test.go generated vendored Normal file
View File

@ -0,0 +1,74 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.9
package main
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"runtime"
"testing"
"golang.org/x/tools/go/buildutil"
)
func TestBundle(t *testing.T) {
load := func(name string) string {
data, err := ioutil.ReadFile(name)
if err != nil {
t.Fatal(err)
}
return string(data)
}
ctxt = buildutil.FakeContext(map[string]map[string]string{
"initial": {
"a.go": load("testdata/src/initial/a.go"),
"b.go": load("testdata/src/initial/b.go"),
"c.go": load("testdata/src/initial/c.go"),
},
"domain.name/importdecl": {
"p.go": load("testdata/src/domain.name/importdecl/p.go"),
},
"fmt": {
"print.go": `package fmt; func Println(...interface{})`,
},
})
os.Args = os.Args[:1] // avoid e.g. -test=short in the output
out, err := bundle("initial", "github.com/dest", "dest", "prefix")
if err != nil {
t.Fatal(err)
}
if got, want := string(out), load("testdata/out.golden"); got != want {
t.Errorf("-- got --\n%s\n-- want --\n%s\n-- diff --", got, want)
if err := ioutil.WriteFile("testdata/out.got", out, 0644); err != nil {
t.Fatal(err)
}
t.Log(diff("testdata/out.golden", "testdata/out.got"))
}
}
func diff(a, b string) string {
var cmd *exec.Cmd
switch runtime.GOOS {
case "plan9":
cmd = exec.Command("/bin/diff", "-c", a, b)
default:
cmd = exec.Command("/usr/bin/diff", "-u", a, b)
}
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
cmd.Run() // nonzero exit is expected
if out.Len() == 0 {
return "(failed to compute diff)"
}
return out.String()
}

View File

@ -0,0 +1,62 @@
// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
// $ bundle
// The package doc comment
//
package dest
import (
"fmt"
. "fmt"
_ "fmt"
renamedfmt "fmt"
renamedfmt2 "fmt"
"domain.name/importdecl"
)
// init functions are not renamed
func init() { prefixfoo() }
// Type S.
type prefixS struct {
prefixt
u int
} /* multi-line
comment
*/
// non-associated comment
/*
non-associated comment2
*/
// Function bar.
func prefixbar(s *prefixS) {
fmt.Println(s.prefixt, s.u) // comment inside function
}
// file-end comment
type prefixt int // type1
// const1
const prefixc = 1 // const2
func prefixfoo() {
fmt.Println(importdecl.F())
}
// zinit
const (
prefixz1 = iota // z1
prefixz2 // z2
) // zend
func prefixbaz() {
renamedfmt.Println()
renamedfmt2.Println()
Println()
}

View File

@ -0,0 +1,3 @@
package importdecl
func F() int { return 1 }

View File

@ -0,0 +1,27 @@
package initial
import "fmt" // this comment should not be visible
// init functions are not renamed
func init() { foo() }
// Type S.
type S struct {
t
u int
} /* multi-line
comment
*/
// non-associated comment
/*
non-associated comment2
*/
// Function bar.
func bar(s *S) {
fmt.Println(s.t, s.u) // comment inside function
}
// file-end comment

View File

@ -0,0 +1,23 @@
// The package doc comment
package initial
import (
"fmt"
"domain.name/importdecl"
)
type t int // type1
// const1
const c = 1 // const2
func foo() {
fmt.Println(importdecl.F())
}
// zinit
const (
z1 = iota // z1
z2 // z2
) // zend

View File

@ -0,0 +1,12 @@
package initial
import _ "fmt"
import renamedfmt "fmt"
import renamedfmt2 "fmt"
import . "fmt"
func baz() {
renamedfmt.Println()
renamedfmt2.Println()
Println()
}

361
vendor/golang.org/x/tools/cmd/callgraph/main.go generated vendored Normal file
View File

@ -0,0 +1,361 @@
// 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.
// callgraph: a tool for reporting the call graph of a Go program.
// See Usage for details, or run with -help.
package main // import "golang.org/x/tools/cmd/callgraph"
// TODO(adonovan):
//
// Features:
// - restrict graph to a single package
// - output
// - functions reachable from root (use digraph tool?)
// - unreachable functions (use digraph tool?)
// - dynamic (runtime) types
// - indexed output (numbered nodes)
// - JSON output
// - additional template fields:
// callee file/line/col
import (
"bufio"
"bytes"
"flag"
"fmt"
"go/build"
"go/token"
"io"
"log"
"os"
"runtime"
"text/template"
"golang.org/x/tools/go/buildutil"
"golang.org/x/tools/go/callgraph"
"golang.org/x/tools/go/callgraph/cha"
"golang.org/x/tools/go/callgraph/rta"
"golang.org/x/tools/go/callgraph/static"
"golang.org/x/tools/go/loader"
"golang.org/x/tools/go/pointer"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/ssautil"
)
// flags
var (
algoFlag = flag.String("algo", "rta",
`Call graph construction algorithm (static, cha, rta, pta)`)
testFlag = flag.Bool("test", false,
"Loads test code (*_test.go) for imported packages")
formatFlag = flag.String("format",
"{{.Caller}}\t--{{.Dynamic}}-{{.Line}}:{{.Column}}-->\t{{.Callee}}",
"A template expression specifying how to format an edge")
ptalogFlag = flag.String("ptalog", "",
"Location of the points-to analysis log file, or empty to disable logging.")
)
func init() {
flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
}
const Usage = `callgraph: display the the call graph of a Go program.
Usage:
callgraph [-algo=static|cha|rta|pta] [-test] [-format=...] <args>...
Flags:
-algo Specifies the call-graph construction algorithm, one of:
static static calls only (unsound)
cha Class Hierarchy Analysis
rta Rapid Type Analysis
pta inclusion-based Points-To Analysis
The algorithms are ordered by increasing precision in their
treatment of dynamic calls (and thus also computational cost).
RTA and PTA require a whole program (main or test), and
include only functions reachable from main.
-test Include the package's tests in the analysis.
-format Specifies the format in which each call graph edge is displayed.
One of:
digraph output suitable for input to
golang.org/x/tools/cmd/digraph.
graphviz output in AT&T GraphViz (.dot) format.
All other values are interpreted using text/template syntax.
The default value is:
{{.Caller}}\t--{{.Dynamic}}-{{.Line}}:{{.Column}}-->\t{{.Callee}}
The structure passed to the template is (effectively):
type Edge struct {
Caller *ssa.Function // calling function
Callee *ssa.Function // called function
// Call site:
Filename string // containing file
Offset int // offset within file of '('
Line int // line number
Column int // column number of call
Dynamic string // "static" or "dynamic"
Description string // e.g. "static method call"
}
Caller and Callee are *ssa.Function values, which print as
"(*sync/atomic.Mutex).Lock", but other attributes may be
derived from them, e.g. Caller.Pkg.Pkg.Path yields the
import path of the enclosing package. Consult the go/ssa
API documentation for details.
` + loader.FromArgsUsage + `
Examples:
Show the call graph of the trivial web server application:
callgraph -format digraph $GOROOT/src/net/http/triv.go
Same, but show only the packages of each function:
callgraph -format '{{.Caller.Pkg.Pkg.Path}} -> {{.Callee.Pkg.Pkg.Path}}' \
$GOROOT/src/net/http/triv.go | sort | uniq
Show functions that make dynamic calls into the 'fmt' test package,
using the pointer analysis algorithm:
callgraph -format='{{.Caller}} -{{.Dynamic}}-> {{.Callee}}' -test -algo=pta fmt |
sed -ne 's/-dynamic-/--/p' |
sed -ne 's/-->.*fmt_test.*$//p' | sort | uniq
Show all functions directly called by the callgraph tool's main function:
callgraph -format=digraph golang.org/x/tools/cmd/callgraph |
digraph succs golang.org/x/tools/cmd/callgraph.main
`
func init() {
// If $GOMAXPROCS isn't set, use the full capacity of the machine.
// For small machines, use at least 4 threads.
if os.Getenv("GOMAXPROCS") == "" {
n := runtime.NumCPU()
if n < 4 {
n = 4
}
runtime.GOMAXPROCS(n)
}
}
func main() {
flag.Parse()
if err := doCallgraph(&build.Default, *algoFlag, *formatFlag, *testFlag, flag.Args()); err != nil {
fmt.Fprintf(os.Stderr, "callgraph: %s\n", err)
os.Exit(1)
}
}
var stdout io.Writer = os.Stdout
func doCallgraph(ctxt *build.Context, algo, format string, tests bool, args []string) error {
conf := loader.Config{Build: ctxt}
if len(args) == 0 {
fmt.Fprintln(os.Stderr, Usage)
return nil
}
// Use the initial packages from the command line.
_, err := conf.FromArgs(args, tests)
if err != nil {
return err
}
// Load, parse and type-check the whole program.
iprog, err := conf.Load()
if err != nil {
return err
}
// Create and build SSA-form program representation.
prog := ssautil.CreateProgram(iprog, 0)
prog.Build()
// -- call graph construction ------------------------------------------
var cg *callgraph.Graph
switch algo {
case "static":
cg = static.CallGraph(prog)
case "cha":
cg = cha.CallGraph(prog)
case "pta":
// Set up points-to analysis log file.
var ptalog io.Writer
if *ptalogFlag != "" {
if f, err := os.Create(*ptalogFlag); err != nil {
log.Fatalf("Failed to create PTA log file: %s", err)
} else {
buf := bufio.NewWriter(f)
ptalog = buf
defer func() {
if err := buf.Flush(); err != nil {
log.Printf("flush: %s", err)
}
if err := f.Close(); err != nil {
log.Printf("close: %s", err)
}
}()
}
}
mains, err := mainPackages(prog, tests)
if err != nil {
return err
}
config := &pointer.Config{
Mains: mains,
BuildCallGraph: true,
Log: ptalog,
}
ptares, err := pointer.Analyze(config)
if err != nil {
return err // internal error in pointer analysis
}
cg = ptares.CallGraph
case "rta":
mains, err := mainPackages(prog, tests)
if err != nil {
return err
}
var roots []*ssa.Function
for _, main := range mains {
roots = append(roots, main.Func("init"), main.Func("main"))
}
rtares := rta.Analyze(roots, true)
cg = rtares.CallGraph
// NB: RTA gives us Reachable and RuntimeTypes too.
default:
return fmt.Errorf("unknown algorithm: %s", algo)
}
cg.DeleteSyntheticNodes()
// -- output------------------------------------------------------------
var before, after string
// Pre-canned formats.
switch format {
case "digraph":
format = `{{printf "%q %q" .Caller .Callee}}`
case "graphviz":
before = "digraph callgraph {\n"
after = "}\n"
format = ` {{printf "%q" .Caller}} -> {{printf "%q" .Callee}}`
}
tmpl, err := template.New("-format").Parse(format)
if err != nil {
return fmt.Errorf("invalid -format template: %v", err)
}
// Allocate these once, outside the traversal.
var buf bytes.Buffer
data := Edge{fset: prog.Fset}
fmt.Fprint(stdout, before)
if err := callgraph.GraphVisitEdges(cg, func(edge *callgraph.Edge) error {
data.position.Offset = -1
data.edge = edge
data.Caller = edge.Caller.Func
data.Callee = edge.Callee.Func
buf.Reset()
if err := tmpl.Execute(&buf, &data); err != nil {
return err
}
stdout.Write(buf.Bytes())
if len := buf.Len(); len == 0 || buf.Bytes()[len-1] != '\n' {
fmt.Fprintln(stdout)
}
return nil
}); err != nil {
return err
}
fmt.Fprint(stdout, after)
return nil
}
// mainPackages returns the main packages to analyze.
// Each resulting package is named "main" and has a main function.
func mainPackages(prog *ssa.Program, tests bool) ([]*ssa.Package, error) {
pkgs := prog.AllPackages() // TODO(adonovan): use only initial packages
// If tests, create a "testmain" package for each test.
var mains []*ssa.Package
if tests {
for _, pkg := range pkgs {
if main := prog.CreateTestMainPackage(pkg); main != nil {
mains = append(mains, main)
}
}
if mains == nil {
return nil, fmt.Errorf("no tests")
}
return mains, nil
}
// Otherwise, use the main packages.
mains = append(mains, ssautil.MainPackages(pkgs)...)
if len(mains) == 0 {
return nil, fmt.Errorf("no main packages")
}
return mains, nil
}
type Edge struct {
Caller *ssa.Function
Callee *ssa.Function
edge *callgraph.Edge
fset *token.FileSet
position token.Position // initialized lazily
}
func (e *Edge) pos() *token.Position {
if e.position.Offset == -1 {
e.position = e.fset.Position(e.edge.Pos()) // called lazily
}
return &e.position
}
func (e *Edge) Filename() string { return e.pos().Filename }
func (e *Edge) Column() int { return e.pos().Column }
func (e *Edge) Line() int { return e.pos().Line }
func (e *Edge) Offset() int { return e.pos().Offset }
func (e *Edge) Dynamic() string {
if e.edge.Site != nil && e.edge.Site.Common().StaticCallee() == nil {
return "dynamic"
}
return "static"
}
func (e *Edge) Description() string { return e.edge.Description() }

81
vendor/golang.org/x/tools/cmd/callgraph/main_test.go generated vendored Normal file
View File

@ -0,0 +1,81 @@
// 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.
// No testdata on Android.
// +build !android
package main
import (
"bytes"
"fmt"
"go/build"
"reflect"
"sort"
"strings"
"testing"
)
func TestCallgraph(t *testing.T) {
ctxt := build.Default // copy
ctxt.GOPATH = "testdata"
const format = "{{.Caller}} --> {{.Callee}}"
for _, test := range []struct {
algo, format string
tests bool
want []string
}{
{"rta", format, false, []string{
// rta imprecisely shows cross product of {main,main2} x {C,D}
`pkg.main --> (pkg.C).f`,
`pkg.main --> (pkg.D).f`,
`pkg.main --> pkg.main2`,
`pkg.main2 --> (pkg.C).f`,
`pkg.main2 --> (pkg.D).f`,
}},
{"pta", format, false, []string{
// pta distinguishes main->C, main2->D. Also has a root node.
`<root> --> pkg.init`,
`<root> --> pkg.main`,
`pkg.main --> (pkg.C).f`,
`pkg.main --> pkg.main2`,
`pkg.main2 --> (pkg.D).f`,
}},
// tests: main is not called.
{"rta", format, true, []string{
`pkg$testmain.init --> pkg.init`,
`pkg.Example --> (pkg.C).f`,
}},
{"pta", format, true, []string{
`<root> --> pkg$testmain.init`,
`<root> --> pkg.Example`,
`pkg$testmain.init --> pkg.init`,
`pkg.Example --> (pkg.C).f`,
}},
} {
stdout = new(bytes.Buffer)
if err := doCallgraph(&ctxt, test.algo, test.format, test.tests, []string{"pkg"}); err != nil {
t.Error(err)
continue
}
got := sortedLines(fmt.Sprint(stdout))
if !reflect.DeepEqual(got, test.want) {
t.Errorf("callgraph(%q, %q, %t):\ngot:\n%s\nwant:\n%s",
test.algo, test.format, test.tests,
strings.Join(got, "\n"),
strings.Join(test.want, "\n"))
}
}
}
func sortedLines(s string) []string {
s = strings.TrimSpace(s)
lines := strings.Split(s, "\n")
sort.Strings(lines)
return lines
}

View File

@ -0,0 +1,25 @@
package main
type I interface {
f()
}
type C int
func (C) f() {}
type D int
func (D) f() {}
func main() {
var i I = C(0)
i.f() // dynamic call
main2()
}
func main2() {
var i I = D(0)
i.f() // dynamic call
}

View File

@ -0,0 +1,7 @@
package main
// Don't import "testing", it adds a lot of callgraph edges.
func Example() {
C(0).f()
}

360
vendor/golang.org/x/tools/cmd/compilebench/main.go generated vendored Normal file
View File

@ -0,0 +1,360 @@
// 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.
// Compilebench benchmarks the speed of the Go compiler.
//
// Usage:
//
// compilebench [options]
//
// It times the compilation of various packages and prints results in
// the format used by package testing (and expected by golang.org/x/perf/cmd/benchstat).
//
// The options are:
//
// -alloc
// Report allocations.
//
// -compile exe
// Use exe as the path to the cmd/compile binary.
//
// -compileflags 'list'
// Pass the space-separated list of flags to the compilation.
//
// -count n
// Run each benchmark n times (default 1).
//
// -cpuprofile file
// Write a CPU profile of the compiler to file.
//
// -memprofile file
// Write a memory profile of the compiler to file.
//
// -memprofilerate rate
// Set runtime.MemProfileRate during compilation.
//
// -obj
// Report object file statistics.
//
// -pkg
// Benchmark compiling a single package.
//
// -run regexp
// Only run benchmarks with names matching regexp.
//
// Although -cpuprofile and -memprofile are intended to write a
// combined profile for all the executed benchmarks to file,
// today they write only the profile for the last benchmark executed.
//
// The default memory profiling rate is one profile sample per 512 kB
// allocated (see ``go doc runtime.MemProfileRate'').
// Lowering the rate (for example, -memprofilerate 64000) produces
// a more fine-grained and therefore accurate profile, but it also incurs
// execution cost. For benchmark comparisons, never use timings
// obtained with a low -memprofilerate option.
//
// Example
//
// Assuming the base version of the compiler has been saved with
// ``toolstash save,'' this sequence compares the old and new compiler:
//
// compilebench -count 10 -compile $(toolstash -n compile) >old.txt
// compilebench -count 10 >new.txt
// benchstat old.txt new.txt
//
package main
import (
"bytes"
"flag"
"fmt"
"go/build"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
)
var (
goroot string
compiler string
runRE *regexp.Regexp
is6g bool
)
var (
flagGoCmd = flag.String("go", "go", "path to \"go\" command")
flagAlloc = flag.Bool("alloc", false, "report allocations")
flagObj = flag.Bool("obj", false, "report object file stats")
flagCompiler = flag.String("compile", "", "use `exe` as the cmd/compile binary")
flagCompilerFlags = flag.String("compileflags", "", "additional `flags` to pass to compile")
flagRun = flag.String("run", "", "run benchmarks matching `regexp`")
flagCount = flag.Int("count", 1, "run benchmarks `n` times")
flagCpuprofile = flag.String("cpuprofile", "", "write CPU profile to `file`")
flagMemprofile = flag.String("memprofile", "", "write memory profile to `file`")
flagMemprofilerate = flag.Int64("memprofilerate", -1, "set memory profile `rate`")
flagPackage = flag.String("pkg", "", "if set, benchmark the package at path `pkg`")
flagShort = flag.Bool("short", false, "skip long-running benchmarks")
)
var tests = []struct {
name string
dir string
long bool
}{
{"BenchmarkTemplate", "html/template", false},
{"BenchmarkUnicode", "unicode", false},
{"BenchmarkGoTypes", "go/types", false},
{"BenchmarkCompiler", "cmd/compile/internal/gc", false},
{"BenchmarkSSA", "cmd/compile/internal/ssa", false},
{"BenchmarkFlate", "compress/flate", false},
{"BenchmarkGoParser", "go/parser", false},
{"BenchmarkReflect", "reflect", false},
{"BenchmarkTar", "archive/tar", false},
{"BenchmarkXML", "encoding/xml", false},
{"BenchmarkStdCmd", "", true},
{"BenchmarkHelloSize", "", false},
{"BenchmarkCmdGoSize", "", true},
}
func usage() {
fmt.Fprintf(os.Stderr, "usage: compilebench [options]\n")
fmt.Fprintf(os.Stderr, "options:\n")
flag.PrintDefaults()
os.Exit(2)
}
func main() {
log.SetFlags(0)
log.SetPrefix("compilebench: ")
flag.Usage = usage
flag.Parse()
if flag.NArg() != 0 {
usage()
}
s, err := exec.Command(*flagGoCmd, "env", "GOROOT").CombinedOutput()
if err != nil {
log.Fatalf("%s env GOROOT: %v", *flagGoCmd, err)
}
goroot = strings.TrimSpace(string(s))
compiler = *flagCompiler
if compiler == "" {
out, err := exec.Command(*flagGoCmd, "tool", "-n", "compile").CombinedOutput()
if err != nil {
out, err = exec.Command(*flagGoCmd, "tool", "-n", "6g").CombinedOutput()
is6g = true
if err != nil {
out, err = exec.Command(*flagGoCmd, "tool", "-n", "compile").CombinedOutput()
log.Fatalf("go tool -n compiler: %v\n%s", err, out)
}
}
compiler = strings.TrimSpace(string(out))
}
if *flagRun != "" {
r, err := regexp.Compile(*flagRun)
if err != nil {
log.Fatalf("invalid -run argument: %v", err)
}
runRE = r
}
for i := 0; i < *flagCount; i++ {
if *flagPackage != "" {
runBuild("BenchmarkPkg", *flagPackage, i)
continue
}
for _, tt := range tests {
if tt.long && *flagShort {
continue
}
if runRE == nil || runRE.MatchString(tt.name) {
runBuild(tt.name, tt.dir, i)
}
}
}
}
func runCmd(name string, cmd *exec.Cmd) {
start := time.Now()
out, err := cmd.CombinedOutput()
if err != nil {
log.Printf("%v: %v\n%s", name, err, out)
return
}
fmt.Printf("%s 1 %d ns/op\n", name, time.Since(start).Nanoseconds())
}
func runStdCmd() {
args := []string{"build", "-a"}
if *flagCompilerFlags != "" {
args = append(args, "-gcflags", *flagCompilerFlags)
}
args = append(args, "std", "cmd")
cmd := exec.Command(*flagGoCmd, args...)
cmd.Dir = filepath.Join(goroot, "src")
runCmd("BenchmarkStdCmd", cmd)
}
// path is either a path to a file ("$GOROOT/test/helloworld.go") or a package path ("cmd/go").
func runSize(name, path string) {
cmd := exec.Command(*flagGoCmd, "build", "-o", "_compilebenchout_", path)
cmd.Stdout = os.Stderr
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Print(err)
return
}
defer os.Remove("_compilebenchout_")
info, err := os.Stat("_compilebenchout_")
if err != nil {
log.Print(err)
return
}
out, err := exec.Command("size", "_compilebenchout_").CombinedOutput()
if err != nil {
log.Printf("size: %v\n%s", err, out)
return
}
lines := strings.Split(string(out), "\n")
if len(lines) < 2 {
log.Printf("not enough output from size: %s", out)
return
}
f := strings.Fields(lines[1])
if strings.HasPrefix(lines[0], "__TEXT") && len(f) >= 2 { // OS X
fmt.Printf("%s 1 %s text-bytes %s data-bytes %v exe-bytes\n", name, f[0], f[1], info.Size())
} else if strings.Contains(lines[0], "bss") && len(f) >= 3 {
fmt.Printf("%s 1 %s text-bytes %s data-bytes %s bss-bytes %v exe-bytes\n", name, f[0], f[1], f[2], info.Size())
}
}
func runBuild(name, dir string, count int) {
switch name {
case "BenchmarkStdCmd":
runStdCmd()
return
case "BenchmarkCmdGoSize":
runSize("BenchmarkCmdGoSize", "cmd/go")
return
case "BenchmarkHelloSize":
runSize("BenchmarkHelloSize", filepath.Join(goroot, "test/helloworld.go"))
return
}
pkg, err := build.Import(dir, ".", 0)
if err != nil {
log.Print(err)
return
}
args := []string{"-o", "_compilebench_.o"}
if is6g {
*flagMemprofilerate = -1
*flagAlloc = false
*flagCpuprofile = ""
*flagMemprofile = ""
}
if *flagMemprofilerate >= 0 {
args = append(args, "-memprofilerate", fmt.Sprint(*flagMemprofilerate))
}
args = append(args, strings.Fields(*flagCompilerFlags)...)
if *flagAlloc || *flagCpuprofile != "" || *flagMemprofile != "" {
if *flagAlloc || *flagMemprofile != "" {
args = append(args, "-memprofile", "_compilebench_.memprof")
}
if *flagCpuprofile != "" {
args = append(args, "-cpuprofile", "_compilebench_.cpuprof")
}
}
args = append(args, pkg.GoFiles...)
cmd := exec.Command(compiler, args...)
cmd.Dir = pkg.Dir
cmd.Stdout = os.Stderr
cmd.Stderr = os.Stderr
start := time.Now()
err = cmd.Run()
if err != nil {
log.Printf("%v: %v", name, err)
return
}
end := time.Now()
var allocs, allocbytes int64
if *flagAlloc || *flagMemprofile != "" {
out, err := ioutil.ReadFile(pkg.Dir + "/_compilebench_.memprof")
if err != nil {
log.Print("cannot find memory profile after compilation")
}
for _, line := range strings.Split(string(out), "\n") {
f := strings.Fields(line)
if len(f) < 4 || f[0] != "#" || f[2] != "=" {
continue
}
val, err := strconv.ParseInt(f[3], 0, 64)
if err != nil {
continue
}
switch f[1] {
case "TotalAlloc":
allocbytes = val
case "Mallocs":
allocs = val
}
}
if *flagMemprofile != "" {
if err := ioutil.WriteFile(*flagMemprofile, out, 0666); err != nil {
log.Print(err)
}
}
os.Remove(pkg.Dir + "/_compilebench_.memprof")
}
if *flagCpuprofile != "" {
out, err := ioutil.ReadFile(pkg.Dir + "/_compilebench_.cpuprof")
if err != nil {
log.Print(err)
}
outpath := *flagCpuprofile
if *flagCount != 1 {
outpath = fmt.Sprintf("%s_%d", outpath, count)
}
if err := ioutil.WriteFile(outpath, out, 0666); err != nil {
log.Print(err)
}
os.Remove(pkg.Dir + "/_compilebench_.cpuprof")
}
wallns := end.Sub(start).Nanoseconds()
userns := cmd.ProcessState.UserTime().Nanoseconds()
fmt.Printf("%s 1 %d ns/op %d user-ns/op", name, wallns, userns)
if *flagAlloc {
fmt.Printf(" %d B/op %d allocs/op", allocbytes, allocs)
}
opath := pkg.Dir + "/_compilebench_.o"
if *flagObj {
// TODO(josharian): object files are big; just read enough to find what we seek.
data, err := ioutil.ReadFile(opath)
if err != nil {
log.Print(err)
}
// Find start of export data.
i := bytes.Index(data, []byte("\n$$B\n")) + len("\n$$B\n")
// Count bytes to end of export data.
nexport := bytes.Index(data[i:], []byte("\n$$\n"))
fmt.Printf(" %d object-bytes %d export-bytes", len(data), nexport)
}
fmt.Println()
os.Remove(opath)
}

2
vendor/golang.org/x/tools/cmd/cover/README generated vendored Normal file
View File

@ -0,0 +1,2 @@
NOTE: For Go releases 1.5 and later, this tool lives in the
standard repository. The code here is not maintained.

722
vendor/golang.org/x/tools/cmd/cover/cover.go generated vendored Normal file
View File

@ -0,0 +1,722 @@
// 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 (
"bytes"
"flag"
"fmt"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
)
const usageMessage = "" +
`Usage of 'go tool cover':
Given a coverage profile produced by 'go test':
go test -coverprofile=c.out
Open a web browser displaying annotated source code:
go tool cover -html=c.out
Write out an HTML file instead of launching a web browser:
go tool cover -html=c.out -o coverage.html
Display coverage percentages to stdout for each function:
go tool cover -func=c.out
Finally, to generate modified source code with coverage annotations
(what go test -cover does):
go tool cover -mode=set -var=CoverageVariableName program.go
`
func usage() {
fmt.Fprintln(os.Stderr, usageMessage)
fmt.Fprintln(os.Stderr, "Flags:")
flag.PrintDefaults()
fmt.Fprintln(os.Stderr, "\n Only one of -html, -func, or -mode may be set.")
os.Exit(2)
}
var (
mode = flag.String("mode", "", "coverage mode: set, count, atomic")
varVar = flag.String("var", "GoCover", "name of coverage variable to generate")
output = flag.String("o", "", "file for output; default: stdout")
htmlOut = flag.String("html", "", "generate HTML representation of coverage profile")
funcOut = flag.String("func", "", "output coverage profile information for each function")
)
var profile string // The profile to read; the value of -html or -func
var counterStmt func(*File, ast.Expr) ast.Stmt
const (
atomicPackagePath = "sync/atomic"
atomicPackageName = "_cover_atomic_"
)
func main() {
flag.Usage = usage
flag.Parse()
// Usage information when no arguments.
if flag.NFlag() == 0 && flag.NArg() == 0 {
flag.Usage()
}
err := parseFlags()
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, `For usage information, run "go tool cover -help"`)
os.Exit(2)
}
// Generate coverage-annotated source.
if *mode != "" {
annotate(flag.Arg(0))
return
}
// Output HTML or function coverage information.
if *htmlOut != "" {
err = htmlOutput(profile, *output)
} else {
err = funcOutput(profile, *output)
}
if err != nil {
fmt.Fprintf(os.Stderr, "cover: %v\n", err)
os.Exit(2)
}
}
// parseFlags sets the profile and counterStmt globals and performs validations.
func parseFlags() error {
profile = *htmlOut
if *funcOut != "" {
if profile != "" {
return fmt.Errorf("too many options")
}
profile = *funcOut
}
// Must either display a profile or rewrite Go source.
if (profile == "") == (*mode == "") {
return fmt.Errorf("too many options")
}
if *mode != "" {
switch *mode {
case "set":
counterStmt = setCounterStmt
case "count":
counterStmt = incCounterStmt
case "atomic":
counterStmt = atomicCounterStmt
default:
return fmt.Errorf("unknown -mode %v", *mode)
}
if flag.NArg() == 0 {
return fmt.Errorf("missing source file")
} else if flag.NArg() == 1 {
return nil
}
} else if flag.NArg() == 0 {
return nil
}
return fmt.Errorf("too many arguments")
}
// Block represents the information about a basic block to be recorded in the analysis.
// Note: Our definition of basic block is based on control structures; we don't break
// apart && and ||. We could but it doesn't seem important enough to bother.
type Block struct {
startByte token.Pos
endByte token.Pos
numStmt int
}
// File is a wrapper for the state of a file used in the parser.
// The basic parse tree walker is a method of this type.
type File struct {
fset *token.FileSet
name string // Name of file.
astFile *ast.File
blocks []Block
atomicPkg string // Package name for "sync/atomic" in this file.
}
// Visit implements the ast.Visitor interface.
func (f *File) Visit(node ast.Node) ast.Visitor {
switch n := node.(type) {
case *ast.BlockStmt:
// If it's a switch or select, the body is a list of case clauses; don't tag the block itself.
if len(n.List) > 0 {
switch n.List[0].(type) {
case *ast.CaseClause: // switch
for _, n := range n.List {
clause := n.(*ast.CaseClause)
clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
}
return f
case *ast.CommClause: // select
for _, n := range n.List {
clause := n.(*ast.CommClause)
clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
}
return f
}
}
n.List = f.addCounters(n.Lbrace, n.Rbrace+1, n.List, true) // +1 to step past closing brace.
case *ast.IfStmt:
ast.Walk(f, n.Body)
if n.Else == nil {
return nil
}
// The elses are special, because if we have
// if x {
// } else if y {
// }
// we want to cover the "if y". To do this, we need a place to drop the counter,
// so we add a hidden block:
// if x {
// } else {
// if y {
// }
// }
switch stmt := n.Else.(type) {
case *ast.IfStmt:
block := &ast.BlockStmt{
Lbrace: n.Body.End(), // Start at end of the "if" block so the covered part looks like it starts at the "else".
List: []ast.Stmt{stmt},
Rbrace: stmt.End(),
}
n.Else = block
case *ast.BlockStmt:
stmt.Lbrace = n.Body.End() // Start at end of the "if" block so the covered part looks like it starts at the "else".
default:
panic("unexpected node type in if")
}
ast.Walk(f, n.Else)
return nil
case *ast.SelectStmt:
// Don't annotate an empty select - creates a syntax error.
if n.Body == nil || len(n.Body.List) == 0 {
return nil
}
case *ast.SwitchStmt:
// Don't annotate an empty switch - creates a syntax error.
if n.Body == nil || len(n.Body.List) == 0 {
return nil
}
case *ast.TypeSwitchStmt:
// Don't annotate an empty type switch - creates a syntax error.
if n.Body == nil || len(n.Body.List) == 0 {
return nil
}
}
return f
}
// unquote returns the unquoted string.
func unquote(s string) string {
t, err := strconv.Unquote(s)
if err != nil {
log.Fatalf("cover: improperly quoted string %q\n", s)
}
return t
}
// addImport adds an import for the specified path, if one does not already exist, and returns
// the local package name.
func (f *File) addImport(path string) string {
// Does the package already import it?
for _, s := range f.astFile.Imports {
if unquote(s.Path.Value) == path {
if s.Name != nil {
return s.Name.Name
}
return filepath.Base(path)
}
}
newImport := &ast.ImportSpec{
Name: ast.NewIdent(atomicPackageName),
Path: &ast.BasicLit{
Kind: token.STRING,
Value: fmt.Sprintf("%q", path),
},
}
impDecl := &ast.GenDecl{
Tok: token.IMPORT,
Specs: []ast.Spec{
newImport,
},
}
// Make the new import the first Decl in the file.
astFile := f.astFile
astFile.Decls = append(astFile.Decls, nil)
copy(astFile.Decls[1:], astFile.Decls[0:])
astFile.Decls[0] = impDecl
astFile.Imports = append(astFile.Imports, newImport)
// Now refer to the package, just in case it ends up unused.
// That is, append to the end of the file the declaration
// var _ = _cover_atomic_.AddUint32
reference := &ast.GenDecl{
Tok: token.VAR,
Specs: []ast.Spec{
&ast.ValueSpec{
Names: []*ast.Ident{
ast.NewIdent("_"),
},
Values: []ast.Expr{
&ast.SelectorExpr{
X: ast.NewIdent(atomicPackageName),
Sel: ast.NewIdent("AddUint32"),
},
},
},
},
}
astFile.Decls = append(astFile.Decls, reference)
return atomicPackageName
}
var slashslash = []byte("//")
// initialComments returns the prefix of content containing only
// whitespace and line comments. Any +build directives must appear
// within this region. This approach is more reliable than using
// go/printer to print a modified AST containing comments.
//
func initialComments(content []byte) []byte {
// Derived from go/build.Context.shouldBuild.
end := 0
p := content
for len(p) > 0 {
line := p
if i := bytes.IndexByte(line, '\n'); i >= 0 {
line, p = line[:i], p[i+1:]
} else {
p = p[len(p):]
}
line = bytes.TrimSpace(line)
if len(line) == 0 { // Blank line.
end = len(content) - len(p)
continue
}
if !bytes.HasPrefix(line, slashslash) { // Not comment line.
break
}
}
return content[:end]
}
func annotate(name string) {
fset := token.NewFileSet()
content, err := ioutil.ReadFile(name)
if err != nil {
log.Fatalf("cover: %s: %s", name, err)
}
parsedFile, err := parser.ParseFile(fset, name, content, parser.ParseComments)
if err != nil {
log.Fatalf("cover: %s: %s", name, err)
}
parsedFile.Comments = trimComments(parsedFile, fset)
file := &File{
fset: fset,
name: name,
astFile: parsedFile,
}
if *mode == "atomic" {
file.atomicPkg = file.addImport(atomicPackagePath)
}
ast.Walk(file, file.astFile)
fd := os.Stdout
if *output != "" {
var err error
fd, err = os.Create(*output)
if err != nil {
log.Fatalf("cover: %s", err)
}
}
fd.Write(initialComments(content)) // Retain '// +build' directives.
file.print(fd)
// After printing the source tree, add some declarations for the counters etc.
// We could do this by adding to the tree, but it's easier just to print the text.
file.addVariables(fd)
}
// trimComments drops all but the //go: comments, some of which are semantically important.
// We drop all others because they can appear in places that cause our counters
// to appear in syntactically incorrect places. //go: appears at the beginning of
// the line and is syntactically safe.
func trimComments(file *ast.File, fset *token.FileSet) []*ast.CommentGroup {
var comments []*ast.CommentGroup
for _, group := range file.Comments {
var list []*ast.Comment
for _, comment := range group.List {
if strings.HasPrefix(comment.Text, "//go:") && fset.Position(comment.Slash).Column == 1 {
list = append(list, comment)
}
}
if list != nil {
comments = append(comments, &ast.CommentGroup{List: list})
}
}
return comments
}
func (f *File) print(w io.Writer) {
printer.Fprint(w, f.fset, f.astFile)
}
// intLiteral returns an ast.BasicLit representing the integer value.
func (f *File) intLiteral(i int) *ast.BasicLit {
node := &ast.BasicLit{
Kind: token.INT,
Value: fmt.Sprint(i),
}
return node
}
// index returns an ast.BasicLit representing the number of counters present.
func (f *File) index() *ast.BasicLit {
return f.intLiteral(len(f.blocks))
}
// setCounterStmt returns the expression: __count[23] = 1.
func setCounterStmt(f *File, counter ast.Expr) ast.Stmt {
return &ast.AssignStmt{
Lhs: []ast.Expr{counter},
Tok: token.ASSIGN,
Rhs: []ast.Expr{f.intLiteral(1)},
}
}
// incCounterStmt returns the expression: __count[23]++.
func incCounterStmt(f *File, counter ast.Expr) ast.Stmt {
return &ast.IncDecStmt{
X: counter,
Tok: token.INC,
}
}
// atomicCounterStmt returns the expression: atomic.AddUint32(&__count[23], 1)
func atomicCounterStmt(f *File, counter ast.Expr) ast.Stmt {
return &ast.ExprStmt{
X: &ast.CallExpr{
Fun: &ast.SelectorExpr{
X: ast.NewIdent(f.atomicPkg),
Sel: ast.NewIdent("AddUint32"),
},
Args: []ast.Expr{&ast.UnaryExpr{
Op: token.AND,
X: counter,
},
f.intLiteral(1),
},
},
}
}
// newCounter creates a new counter expression of the appropriate form.
func (f *File) newCounter(start, end token.Pos, numStmt int) ast.Stmt {
counter := &ast.IndexExpr{
X: &ast.SelectorExpr{
X: ast.NewIdent(*varVar),
Sel: ast.NewIdent("Count"),
},
Index: f.index(),
}
stmt := counterStmt(f, counter)
f.blocks = append(f.blocks, Block{start, end, numStmt})
return stmt
}
// addCounters takes a list of statements and adds counters to the beginning of
// each basic block at the top level of that list. For instance, given
//
// S1
// if cond {
// S2
// }
// S3
//
// counters will be added before S1 and before S3. The block containing S2
// will be visited in a separate call.
// TODO: Nested simple blocks get unnecessary (but correct) counters
func (f *File) addCounters(pos, blockEnd token.Pos, list []ast.Stmt, extendToClosingBrace bool) []ast.Stmt {
// Special case: make sure we add a counter to an empty block. Can't do this below
// or we will add a counter to an empty statement list after, say, a return statement.
if len(list) == 0 {
return []ast.Stmt{f.newCounter(pos, blockEnd, 0)}
}
// We have a block (statement list), but it may have several basic blocks due to the
// appearance of statements that affect the flow of control.
var newList []ast.Stmt
for {
// Find first statement that affects flow of control (break, continue, if, etc.).
// It will be the last statement of this basic block.
var last int
end := blockEnd
for last = 0; last < len(list); last++ {
end = f.statementBoundary(list[last])
if f.endsBasicSourceBlock(list[last]) {
extendToClosingBrace = false // Block is broken up now.
last++
break
}
}
if extendToClosingBrace {
end = blockEnd
}
if pos != end { // Can have no source to cover if e.g. blocks abut.
newList = append(newList, f.newCounter(pos, end, last))
}
newList = append(newList, list[0:last]...)
list = list[last:]
if len(list) == 0 {
break
}
pos = list[0].Pos()
}
return newList
}
// hasFuncLiteral reports the existence and position of the first func literal
// in the node, if any. If a func literal appears, it usually marks the termination
// of a basic block because the function body is itself a block.
// Therefore we draw a line at the start of the body of the first function literal we find.
// TODO: what if there's more than one? Probably doesn't matter much.
func hasFuncLiteral(n ast.Node) (bool, token.Pos) {
if n == nil {
return false, 0
}
var literal funcLitFinder
ast.Walk(&literal, n)
return literal.found(), token.Pos(literal)
}
// statementBoundary finds the location in s that terminates the current basic
// block in the source.
func (f *File) statementBoundary(s ast.Stmt) token.Pos {
// Control flow statements are easy.
switch s := s.(type) {
case *ast.BlockStmt:
// Treat blocks like basic blocks to avoid overlapping counters.
return s.Lbrace
case *ast.IfStmt:
found, pos := hasFuncLiteral(s.Init)
if found {
return pos
}
found, pos = hasFuncLiteral(s.Cond)
if found {
return pos
}
return s.Body.Lbrace
case *ast.ForStmt:
found, pos := hasFuncLiteral(s.Init)
if found {
return pos
}
found, pos = hasFuncLiteral(s.Cond)
if found {
return pos
}
found, pos = hasFuncLiteral(s.Post)
if found {
return pos
}
return s.Body.Lbrace
case *ast.LabeledStmt:
return f.statementBoundary(s.Stmt)
case *ast.RangeStmt:
found, pos := hasFuncLiteral(s.X)
if found {
return pos
}
return s.Body.Lbrace
case *ast.SwitchStmt:
found, pos := hasFuncLiteral(s.Init)
if found {
return pos
}
found, pos = hasFuncLiteral(s.Tag)
if found {
return pos
}
return s.Body.Lbrace
case *ast.SelectStmt:
return s.Body.Lbrace
case *ast.TypeSwitchStmt:
found, pos := hasFuncLiteral(s.Init)
if found {
return pos
}
return s.Body.Lbrace
}
// If not a control flow statement, it is a declaration, expression, call, etc. and it may have a function literal.
// If it does, that's tricky because we want to exclude the body of the function from this block.
// Draw a line at the start of the body of the first function literal we find.
// TODO: what if there's more than one? Probably doesn't matter much.
found, pos := hasFuncLiteral(s)
if found {
return pos
}
return s.End()
}
// endsBasicSourceBlock reports whether s changes the flow of control: break, if, etc.,
// or if it's just problematic, for instance contains a function literal, which will complicate
// accounting due to the block-within-an expression.
func (f *File) endsBasicSourceBlock(s ast.Stmt) bool {
switch s := s.(type) {
case *ast.BlockStmt:
// Treat blocks like basic blocks to avoid overlapping counters.
return true
case *ast.BranchStmt:
return true
case *ast.ForStmt:
return true
case *ast.IfStmt:
return true
case *ast.LabeledStmt:
return f.endsBasicSourceBlock(s.Stmt)
case *ast.RangeStmt:
return true
case *ast.SwitchStmt:
return true
case *ast.SelectStmt:
return true
case *ast.TypeSwitchStmt:
return true
case *ast.ExprStmt:
// Calls to panic change the flow.
// We really should verify that "panic" is the predefined function,
// but without type checking we can't and the likelihood of it being
// an actual problem is vanishingly small.
if call, ok := s.X.(*ast.CallExpr); ok {
if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "panic" && len(call.Args) == 1 {
return true
}
}
}
found, _ := hasFuncLiteral(s)
return found
}
// funcLitFinder implements the ast.Visitor pattern to find the location of any
// function literal in a subtree.
type funcLitFinder token.Pos
func (f *funcLitFinder) Visit(node ast.Node) (w ast.Visitor) {
if f.found() {
return nil // Prune search.
}
switch n := node.(type) {
case *ast.FuncLit:
*f = funcLitFinder(n.Body.Lbrace)
return nil // Prune search.
}
return f
}
func (f *funcLitFinder) found() bool {
return token.Pos(*f) != token.NoPos
}
// Sort interface for []block1; used for self-check in addVariables.
type block1 struct {
Block
index int
}
type blockSlice []block1
func (b blockSlice) Len() int { return len(b) }
func (b blockSlice) Less(i, j int) bool { return b[i].startByte < b[j].startByte }
func (b blockSlice) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
// offset translates a token position into a 0-indexed byte offset.
func (f *File) offset(pos token.Pos) int {
return f.fset.Position(pos).Offset
}
// addVariables adds to the end of the file the declarations to set up the counter and position variables.
func (f *File) addVariables(w io.Writer) {
// Self-check: Verify that the instrumented basic blocks are disjoint.
t := make([]block1, len(f.blocks))
for i := range f.blocks {
t[i].Block = f.blocks[i]
t[i].index = i
}
sort.Sort(blockSlice(t))
for i := 1; i < len(t); i++ {
if t[i-1].endByte > t[i].startByte {
fmt.Fprintf(os.Stderr, "cover: internal error: block %d overlaps block %d\n", t[i-1].index, t[i].index)
// Note: error message is in byte positions, not token positions.
fmt.Fprintf(os.Stderr, "\t%s:#%d,#%d %s:#%d,#%d\n",
f.name, f.offset(t[i-1].startByte), f.offset(t[i-1].endByte),
f.name, f.offset(t[i].startByte), f.offset(t[i].endByte))
}
}
// Declare the coverage struct as a package-level variable.
fmt.Fprintf(w, "\nvar %s = struct {\n", *varVar)
fmt.Fprintf(w, "\tCount [%d]uint32\n", len(f.blocks))
fmt.Fprintf(w, "\tPos [3 * %d]uint32\n", len(f.blocks))
fmt.Fprintf(w, "\tNumStmt [%d]uint16\n", len(f.blocks))
fmt.Fprintf(w, "} {\n")
// Initialize the position array field.
fmt.Fprintf(w, "\tPos: [3 * %d]uint32{\n", len(f.blocks))
// A nice long list of positions. Each position is encoded as follows to reduce size:
// - 32-bit starting line number
// - 32-bit ending line number
// - (16 bit ending column number << 16) | (16-bit starting column number).
for i, block := range f.blocks {
start := f.fset.Position(block.startByte)
end := f.fset.Position(block.endByte)
fmt.Fprintf(w, "\t\t%d, %d, %#x, // [%d]\n", start.Line, end.Line, (end.Column&0xFFFF)<<16|(start.Column&0xFFFF), i)
}
// Close the position array.
fmt.Fprintf(w, "\t},\n")
// Initialize the position array field.
fmt.Fprintf(w, "\tNumStmt: [%d]uint16{\n", len(f.blocks))
// A nice long list of statements-per-block, so we can give a conventional
// valuation of "percent covered". To save space, it's a 16-bit number, so we
// clamp it if it overflows - won't matter in practice.
for i, block := range f.blocks {
n := block.numStmt
if n > 1<<16-1 {
n = 1<<16 - 1
}
fmt.Fprintf(w, "\t\t%d, // %d\n", n, i)
}
// Close the statements-per-block array.
fmt.Fprintf(w, "\t},\n")
// Close the struct initialization.
fmt.Fprintf(w, "}\n")
}

94
vendor/golang.org/x/tools/cmd/cover/cover_test.go generated vendored Normal file
View File

@ -0,0 +1,94 @@
// 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.
// No testdata on Android.
// +build !android
package main_test
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"testing"
)
const (
// Data directory, also the package directory for the test.
testdata = "testdata"
// Binaries we compile.
testcover = "./testcover.exe"
)
var (
// Files we use.
testMain = filepath.Join(testdata, "main.go")
testTest = filepath.Join(testdata, "test.go")
coverInput = filepath.Join(testdata, "test_line.go")
coverOutput = filepath.Join(testdata, "test_cover.go")
)
var debug = false // Keeps the rewritten files around if set.
// Run this shell script, but do it in Go so it can be run by "go test".
//
// replace the word LINE with the line number < testdata/test.go > testdata/test_line.go
// go build -o ./testcover
// ./testcover -mode=count -var=CoverTest -o ./testdata/test_cover.go testdata/test_line.go
// go run ./testdata/main.go ./testdata/test.go
//
func TestCover(t *testing.T) {
// Read in the test file (testTest) and write it, with LINEs specified, to coverInput.
file, err := ioutil.ReadFile(testTest)
if err != nil {
t.Fatal(err)
}
lines := bytes.Split(file, []byte("\n"))
for i, line := range lines {
lines[i] = bytes.Replace(line, []byte("LINE"), []byte(fmt.Sprint(i+1)), -1)
}
err = ioutil.WriteFile(coverInput, bytes.Join(lines, []byte("\n")), 0666)
if err != nil {
t.Fatal(err)
}
// defer removal of test_line.go
if !debug {
defer os.Remove(coverInput)
}
// go build -o testcover
cmd := exec.Command("go", "build", "-o", testcover)
run(cmd, t)
// defer removal of testcover
defer os.Remove(testcover)
// ./testcover -mode=count -var=coverTest -o ./testdata/test_cover.go testdata/test_line.go
cmd = exec.Command(testcover, "-mode=count", "-var=coverTest", "-o", coverOutput, coverInput)
run(cmd, t)
// defer removal of ./testdata/test_cover.go
if !debug {
defer os.Remove(coverOutput)
}
// go run ./testdata/main.go ./testdata/test.go
cmd = exec.Command("go", "run", testMain, coverOutput)
run(cmd, t)
}
func run(c *exec.Cmd, t *testing.T) {
c.Stdout = os.Stdout
c.Stderr = os.Stderr
err := c.Run()
if err != nil {
t.Fatal(err)
}
}

27
vendor/golang.org/x/tools/cmd/cover/doc.go generated vendored Normal file
View File

@ -0,0 +1,27 @@
// 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.
/*
Cover is a program for analyzing the coverage profiles generated by
'go test -coverprofile=cover.out'.
Cover is also used by 'go test -cover' to rewrite the source code with
annotations to track which parts of each function are executed.
It operates on one Go source file at a time, computing approximate
basic block information by studying the source. It is thus more portable
than binary-rewriting coverage tools, but also a little less capable.
For instance, it does not probe inside && and || expressions, and can
be mildly confused by single statements with multiple function literals.
For usage information, please see:
go help testflag
go tool cover -help
No longer maintained:
For Go releases 1.5 and later, this tool lives in the
standard repository. The code here is not maintained.
*/
package main // import "golang.org/x/tools/cmd/cover"

166
vendor/golang.org/x/tools/cmd/cover/func.go generated vendored Normal file
View File

@ -0,0 +1,166 @@
// 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 implements the visitor that computes the (line, column)-(line-column) range for each function.
package main
import (
"bufio"
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/token"
"os"
"path/filepath"
"text/tabwriter"
"golang.org/x/tools/cover"
)
// funcOutput takes two file names as arguments, a coverage profile to read as input and an output
// file to write ("" means to write to standard output). The function reads the profile and produces
// as output the coverage data broken down by function, like this:
//
// fmt/format.go:30: init 100.0%
// fmt/format.go:57: clearflags 100.0%
// ...
// fmt/scan.go:1046: doScan 100.0%
// fmt/scan.go:1075: advance 96.2%
// fmt/scan.go:1119: doScanf 96.8%
// total: (statements) 91.9%
func funcOutput(profile, outputFile string) error {
profiles, err := cover.ParseProfiles(profile)
if err != nil {
return err
}
var out *bufio.Writer
if outputFile == "" {
out = bufio.NewWriter(os.Stdout)
} else {
fd, err := os.Create(outputFile)
if err != nil {
return err
}
defer fd.Close()
out = bufio.NewWriter(fd)
}
defer out.Flush()
tabber := tabwriter.NewWriter(out, 1, 8, 1, '\t', 0)
defer tabber.Flush()
var total, covered int64
for _, profile := range profiles {
fn := profile.FileName
file, err := findFile(fn)
if err != nil {
return err
}
funcs, err := findFuncs(file)
if err != nil {
return err
}
// Now match up functions and profile blocks.
for _, f := range funcs {
c, t := f.coverage(profile)
fmt.Fprintf(tabber, "%s:%d:\t%s\t%.1f%%\n", fn, f.startLine, f.name, 100.0*float64(c)/float64(t))
total += t
covered += c
}
}
fmt.Fprintf(tabber, "total:\t(statements)\t%.1f%%\n", 100.0*float64(covered)/float64(total))
return nil
}
// findFuncs parses the file and returns a slice of FuncExtent descriptors.
func findFuncs(name string) ([]*FuncExtent, error) {
fset := token.NewFileSet()
parsedFile, err := parser.ParseFile(fset, name, nil, 0)
if err != nil {
return nil, err
}
visitor := &FuncVisitor{
fset: fset,
name: name,
astFile: parsedFile,
}
ast.Walk(visitor, visitor.astFile)
return visitor.funcs, nil
}
// FuncExtent describes a function's extent in the source by file and position.
type FuncExtent struct {
name string
startLine int
startCol int
endLine int
endCol int
}
// FuncVisitor implements the visitor that builds the function position list for a file.
type FuncVisitor struct {
fset *token.FileSet
name string // Name of file.
astFile *ast.File
funcs []*FuncExtent
}
// Visit implements the ast.Visitor interface.
func (v *FuncVisitor) Visit(node ast.Node) ast.Visitor {
switch n := node.(type) {
case *ast.FuncDecl:
start := v.fset.Position(n.Pos())
end := v.fset.Position(n.End())
fe := &FuncExtent{
name: n.Name.Name,
startLine: start.Line,
startCol: start.Column,
endLine: end.Line,
endCol: end.Column,
}
v.funcs = append(v.funcs, fe)
}
return v
}
// coverage returns the fraction of the statements in the function that were covered, as a numerator and denominator.
func (f *FuncExtent) coverage(profile *cover.Profile) (num, den int64) {
// We could avoid making this n^2 overall by doing a single scan and annotating the functions,
// but the sizes of the data structures is never very large and the scan is almost instantaneous.
var covered, total int64
// The blocks are sorted, so we can stop counting as soon as we reach the end of the relevant block.
for _, b := range profile.Blocks {
if b.StartLine > f.endLine || (b.StartLine == f.endLine && b.StartCol >= f.endCol) {
// Past the end of the function.
break
}
if b.EndLine < f.startLine || (b.EndLine == f.startLine && b.EndCol <= f.startCol) {
// Before the beginning of the function
continue
}
total += int64(b.NumStmt)
if b.Count > 0 {
covered += int64(b.NumStmt)
}
}
if total == 0 {
total = 1 // Avoid zero denominator.
}
return covered, total
}
// findFile finds the location of the named file in GOROOT, GOPATH etc.
func findFile(file string) (string, error) {
dir, file := filepath.Split(file)
pkg, err := build.Import(dir, ".", build.FindOnly)
if err != nil {
return "", fmt.Errorf("can't find %q: %v", file, err)
}
return filepath.Join(pkg.Dir, file), nil
}

284
vendor/golang.org/x/tools/cmd/cover/html.go generated vendored Normal file
View File

@ -0,0 +1,284 @@
// 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 (
"bufio"
"bytes"
"fmt"
"html/template"
"io"
"io/ioutil"
"math"
"os"
"os/exec"
"path/filepath"
"runtime"
"golang.org/x/tools/cover"
)
// htmlOutput reads the profile data from profile and generates an HTML
// coverage report, writing it to outfile. If outfile is empty,
// it writes the report to a temporary file and opens it in a web browser.
func htmlOutput(profile, outfile string) error {
profiles, err := cover.ParseProfiles(profile)
if err != nil {
return err
}
var d templateData
for _, profile := range profiles {
fn := profile.FileName
if profile.Mode == "set" {
d.Set = true
}
file, err := findFile(fn)
if err != nil {
return err
}
src, err := ioutil.ReadFile(file)
if err != nil {
return fmt.Errorf("can't read %q: %v", fn, err)
}
var buf bytes.Buffer
err = htmlGen(&buf, src, profile.Boundaries(src))
if err != nil {
return err
}
d.Files = append(d.Files, &templateFile{
Name: fn,
Body: template.HTML(buf.String()),
Coverage: percentCovered(profile),
})
}
var out *os.File
if outfile == "" {
var dir string
dir, err = ioutil.TempDir("", "cover")
if err != nil {
return err
}
out, err = os.Create(filepath.Join(dir, "coverage.html"))
} else {
out, err = os.Create(outfile)
}
if err != nil {
return err
}
err = htmlTemplate.Execute(out, d)
if err == nil {
err = out.Close()
}
if err != nil {
return err
}
if outfile == "" {
if !startBrowser("file://" + out.Name()) {
fmt.Fprintf(os.Stderr, "HTML output written to %s\n", out.Name())
}
}
return nil
}
// percentCovered returns, as a percentage, the fraction of the statements in
// the profile covered by the test run.
// In effect, it reports the coverage of a given source file.
func percentCovered(p *cover.Profile) float64 {
var total, covered int64
for _, b := range p.Blocks {
total += int64(b.NumStmt)
if b.Count > 0 {
covered += int64(b.NumStmt)
}
}
if total == 0 {
return 0
}
return float64(covered) / float64(total) * 100
}
// htmlGen generates an HTML coverage report with the provided filename,
// source code, and tokens, and writes it to the given Writer.
func htmlGen(w io.Writer, src []byte, boundaries []cover.Boundary) error {
dst := bufio.NewWriter(w)
for i := range src {
for len(boundaries) > 0 && boundaries[0].Offset == i {
b := boundaries[0]
if b.Start {
n := 0
if b.Count > 0 {
n = int(math.Floor(b.Norm*9)) + 1
}
fmt.Fprintf(dst, `<span class="cov%v" title="%v">`, n, b.Count)
} else {
dst.WriteString("</span>")
}
boundaries = boundaries[1:]
}
switch b := src[i]; b {
case '>':
dst.WriteString("&gt;")
case '<':
dst.WriteString("&lt;")
case '&':
dst.WriteString("&amp;")
case '\t':
dst.WriteString(" ")
default:
dst.WriteByte(b)
}
}
return dst.Flush()
}
// startBrowser tries to open the URL in a browser
// and reports whether it succeeds.
func startBrowser(url string) bool {
// try to start the browser
var args []string
switch runtime.GOOS {
case "darwin":
args = []string{"open"}
case "windows":
args = []string{"cmd", "/c", "start"}
default:
args = []string{"xdg-open"}
}
cmd := exec.Command(args[0], append(args[1:], url)...)
return cmd.Start() == nil
}
// rgb returns an rgb value for the specified coverage value
// between 0 (no coverage) and 10 (max coverage).
func rgb(n int) string {
if n == 0 {
return "rgb(192, 0, 0)" // Red
}
// Gradient from gray to green.
r := 128 - 12*(n-1)
g := 128 + 12*(n-1)
b := 128 + 3*(n-1)
return fmt.Sprintf("rgb(%v, %v, %v)", r, g, b)
}
// colors generates the CSS rules for coverage colors.
func colors() template.CSS {
var buf bytes.Buffer
for i := 0; i < 11; i++ {
fmt.Fprintf(&buf, ".cov%v { color: %v }\n", i, rgb(i))
}
return template.CSS(buf.String())
}
var htmlTemplate = template.Must(template.New("html").Funcs(template.FuncMap{
"colors": colors,
}).Parse(tmplHTML))
type templateData struct {
Files []*templateFile
Set bool
}
type templateFile struct {
Name string
Body template.HTML
Coverage float64
}
const tmplHTML = `
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
body {
background: black;
color: rgb(80, 80, 80);
}
body, pre, #legend span {
font-family: Menlo, monospace;
font-weight: bold;
}
#topbar {
background: black;
position: fixed;
top: 0; left: 0; right: 0;
height: 42px;
border-bottom: 1px solid rgb(80, 80, 80);
}
#content {
margin-top: 50px;
}
#nav, #legend {
float: left;
margin-left: 10px;
}
#legend {
margin-top: 12px;
}
#nav {
margin-top: 10px;
}
#legend span {
margin: 0 5px;
}
{{colors}}
</style>
</head>
<body>
<div id="topbar">
<div id="nav">
<select id="files">
{{range $i, $f := .Files}}
<option value="file{{$i}}">{{$f.Name}} ({{printf "%.1f" $f.Coverage}}%)</option>
{{end}}
</select>
</div>
<div id="legend">
<span>not tracked</span>
{{if .Set}}
<span class="cov0">not covered</span>
<span class="cov8">covered</span>
{{else}}
<span class="cov0">no coverage</span>
<span class="cov1">low coverage</span>
<span class="cov2">*</span>
<span class="cov3">*</span>
<span class="cov4">*</span>
<span class="cov5">*</span>
<span class="cov6">*</span>
<span class="cov7">*</span>
<span class="cov8">*</span>
<span class="cov9">*</span>
<span class="cov10">high coverage</span>
{{end}}
</div>
</div>
<div id="content">
{{range $i, $f := .Files}}
<pre class="file" id="file{{$i}}" {{if $i}}style="display: none"{{end}}>{{$f.Body}}</pre>
{{end}}
</div>
</body>
<script>
(function() {
var files = document.getElementById('files');
var visible = document.getElementById('file0');
files.addEventListener('change', onChange, false);
function onChange() {
visible.style.display = 'none';
visible = document.getElementById(files.value);
visible.style.display = 'block';
window.scrollTo(0, 0);
}
})();
</script>
</html>
`

112
vendor/golang.org/x/tools/cmd/cover/testdata/main.go generated vendored Normal file
View File

@ -0,0 +1,112 @@
// 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.
// Test runner for coverage test. This file is not coverage-annotated; test.go is.
// It knows the coverage counter is called "coverTest".
package main
import (
"fmt"
"os"
)
func main() {
testAll()
verify()
}
type block struct {
count uint32
line uint32
}
var counters = make(map[block]bool)
// check records the location and expected value for a counter.
func check(line, count uint32) {
b := block{
count,
line,
}
counters[b] = true
}
// checkVal is a version of check that returns its extra argument,
// so it can be used in conditionals.
func checkVal(line, count uint32, val int) int {
b := block{
count,
line,
}
counters[b] = true
return val
}
var PASS = true
// verify checks the expected counts against the actual. It runs after the test has completed.
func verify() {
for b := range counters {
got, index := count(b.line)
if b.count == anything && got != 0 {
got = anything
}
if got != b.count {
fmt.Fprintf(os.Stderr, "test_go:%d expected count %d got %d [counter %d]\n", b.line, b.count, got, index)
PASS = false
}
}
verifyPanic()
if !PASS {
fmt.Fprintf(os.Stderr, "FAIL\n")
os.Exit(2)
}
}
// verifyPanic is a special check for the known counter that should be
// after the panic call in testPanic.
func verifyPanic() {
if coverTest.Count[panicIndex-1] != 1 {
// Sanity check for test before panic.
fmt.Fprintf(os.Stderr, "bad before panic")
PASS = false
}
if coverTest.Count[panicIndex] != 0 {
fmt.Fprintf(os.Stderr, "bad at panic: %d should be 0\n", coverTest.Count[panicIndex])
PASS = false
}
if coverTest.Count[panicIndex+1] != 1 {
fmt.Fprintf(os.Stderr, "bad after panic")
PASS = false
}
}
// count returns the count and index for the counter at the specified line.
func count(line uint32) (uint32, int) {
// Linear search is fine. Choose perfect fit over approximate.
// We can have a closing brace for a range on the same line as a condition for an "else if"
// and we don't want that brace to steal the count for the condition on the "if".
// Therefore we test for a perfect (lo==line && hi==line) match, but if we can't
// find that we take the first imperfect match.
index := -1
indexLo := uint32(1e9)
for i := range coverTest.Count {
lo, hi := coverTest.Pos[3*i], coverTest.Pos[3*i+1]
if lo == line && line == hi {
return coverTest.Count[i], i
}
// Choose the earliest match (the counters are in unpredictable order).
if lo <= line && line <= hi && indexLo > lo {
index = i
indexLo = lo
}
}
if index == -1 {
fmt.Fprintln(os.Stderr, "cover_test: no counter for line", line)
PASS = false
return 0, 0
}
return coverTest.Count[index], index
}

218
vendor/golang.org/x/tools/cmd/cover/testdata/test.go generated vendored Normal file
View File

@ -0,0 +1,218 @@
// 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 program is processed by the cover command, and then testAll is called.
// The test driver in main.go can then compare the coverage statistics with expectation.
// The word LINE is replaced by the line number in this file. When the file is executed,
// the coverage processing has changed the line numbers, so we can't use runtime.Caller.
package main
const anything = 1e9 // Just some unlikely value that means "we got here, don't care how often"
func testAll() {
testSimple()
testBlockRun()
testIf()
testFor()
testRange()
testSwitch()
testTypeSwitch()
testSelect1()
testSelect2()
testPanic()
testEmptySwitches()
}
// The indexes of the counters in testPanic are known to main.go
const panicIndex = 3
// This test appears first because the index of its counters is known to main.go
func testPanic() {
defer func() {
recover()
}()
check(LINE, 1)
panic("should not get next line")
check(LINE, 0) // this is GoCover.Count[panicIndex]
// The next counter is in testSimple and it will be non-zero.
// If the panic above does not trigger a counter, the test will fail
// because GoCover.Count[panicIndex] will be the one in testSimple.
}
func testSimple() {
check(LINE, 1)
}
func testIf() {
if true {
check(LINE, 1)
} else {
check(LINE, 0)
}
if false {
check(LINE, 0)
} else {
check(LINE, 1)
}
for i := 0; i < 3; i++ {
if checkVal(LINE, 3, i) <= 2 {
check(LINE, 3)
}
if checkVal(LINE, 3, i) <= 1 {
check(LINE, 2)
}
if checkVal(LINE, 3, i) <= 0 {
check(LINE, 1)
}
}
for i := 0; i < 3; i++ {
if checkVal(LINE, 3, i) <= 1 {
check(LINE, 2)
} else {
check(LINE, 1)
}
}
for i := 0; i < 3; i++ {
if checkVal(LINE, 3, i) <= 0 {
check(LINE, 1)
} else if checkVal(LINE, 2, i) <= 1 {
check(LINE, 1)
} else if checkVal(LINE, 1, i) <= 2 {
check(LINE, 1)
} else if checkVal(LINE, 0, i) <= 3 {
check(LINE, 0)
}
}
if func(a, b int) bool { return a < b }(3, 4) {
check(LINE, 1)
}
}
func testFor() {
for i := 0; i < 10; func() { i++; check(LINE, 10) }() {
check(LINE, 10)
}
}
func testRange() {
for _, f := range []func(){
func() { check(LINE, 1) },
} {
f()
check(LINE, 1)
}
}
func testBlockRun() {
check(LINE, 1)
{
check(LINE, 1)
}
{
check(LINE, 1)
}
check(LINE, 1)
{
check(LINE, 1)
}
{
check(LINE, 1)
}
check(LINE, 1)
}
func testSwitch() {
for i := 0; i < 5; func() { i++; check(LINE, 5) }() {
switch i {
case 0:
check(LINE, 1)
case 1:
check(LINE, 1)
case 2:
check(LINE, 1)
default:
check(LINE, 2)
}
}
}
func testTypeSwitch() {
var x = []interface{}{1, 2.0, "hi"}
for _, v := range x {
switch func() { check(LINE, 3) }(); v.(type) {
case int:
check(LINE, 1)
case float64:
check(LINE, 1)
case string:
check(LINE, 1)
case complex128:
check(LINE, 0)
default:
check(LINE, 0)
}
}
}
func testSelect1() {
c := make(chan int)
go func() {
for i := 0; i < 1000; i++ {
c <- i
}
}()
for {
select {
case <-c:
check(LINE, anything)
case <-c:
check(LINE, anything)
default:
check(LINE, 1)
return
}
}
}
func testSelect2() {
c1 := make(chan int, 1000)
c2 := make(chan int, 1000)
for i := 0; i < 1000; i++ {
c1 <- i
c2 <- i
}
for {
select {
case <-c1:
check(LINE, 1000)
case <-c2:
check(LINE, 1000)
default:
check(LINE, 1)
return
}
}
}
// Empty control statements created syntax errors. This function
// is here just to be sure that those are handled correctly now.
func testEmptySwitches() {
check(LINE, 1)
switch 3 {
}
check(LINE, 1)
switch i := (interface{})(3).(int); i {
}
check(LINE, 1)
c := make(chan int)
go func() {
check(LINE, 1)
c <- 1
select {}
}()
<-c
check(LINE, 1)
}

540
vendor/golang.org/x/tools/cmd/digraph/digraph.go generated vendored Normal file
View File

@ -0,0 +1,540 @@
// The digraph command performs queries over unlabelled directed graphs
// represented in text form. It is intended to integrate nicely with
// typical UNIX command pipelines.
//
// Since directed graphs (import graphs, reference graphs, call graphs,
// etc) often arise during software tool development and debugging, this
// command is included in the go.tools repository.
//
// TODO(adonovan):
// - support input files other than stdin
// - suport alternative formats (AT&T GraphViz, CSV, etc),
// a comment syntax, etc.
// - allow queries to nest, like Blaze query language.
//
package main // import "golang.org/x/tools/cmd/digraph"
import (
"bufio"
"bytes"
"errors"
"flag"
"fmt"
"io"
"os"
"sort"
"strconv"
"unicode"
"unicode/utf8"
)
const Usage = `digraph: queries over directed graphs in text form.
Graph format:
Each line contains zero or more words. Words are separated by
unquoted whitespace; words may contain Go-style double-quoted portions,
allowing spaces and other characters to be expressed.
Each field declares a node, and if there are more than one,
an edge from the first to each subsequent one.
The graph is provided on the standard input.
For instance, the following (acyclic) graph specifies a partial order
among the subtasks of getting dressed:
% cat clothes.txt
socks shoes
"boxer shorts" pants
pants belt shoes
shirt tie sweater
sweater jacket
hat
The line "shirt tie sweater" indicates the two edges shirt -> tie and
shirt -> sweater, not shirt -> tie -> sweater.
Supported queries:
nodes
the set of all nodes
degree
the in-degree and out-degree of each node.
preds <label> ...
the set of immediate predecessors of the specified nodes
succs <label> ...
the set of immediate successors of the specified nodes
forward <label> ...
the set of nodes transitively reachable from the specified nodes
reverse <label> ...
the set of nodes that transitively reach the specified nodes
somepath <label> <label>
the list of nodes on some arbitrary path from the first node to the second
allpaths <label> <label>
the set of nodes on all paths from the first node to the second
sccs
all strongly connected components (one per line)
scc <label>
the set of nodes nodes strongly connected to the specified one
Example usage:
Show the transitive closure of imports of the digraph tool itself:
% go list -f '{{.ImportPath}}{{.Imports}}' ... | tr '[]' ' ' |
digraph forward golang.org/x/tools/cmd/digraph
Show which clothes (see above) must be donned before a jacket:
% digraph reverse jacket <clothes.txt
`
func main() {
flag.Parse()
args := flag.Args()
if len(args) == 0 {
fmt.Println(Usage)
return
}
if err := digraph(args[0], args[1:]); err != nil {
fmt.Fprintf(os.Stderr, "digraph: %s\n", err)
os.Exit(1)
}
}
type nodelist []string
func (l nodelist) println(sep string) {
for i, label := range l {
if i > 0 {
fmt.Fprint(stdout, sep)
}
fmt.Fprint(stdout, label)
}
fmt.Fprintln(stdout)
}
type nodeset map[string]bool
func (s nodeset) sort() nodelist {
labels := make(nodelist, len(s))
var i int
for label := range s {
labels[i] = label
i++
}
sort.Strings(labels)
return labels
}
func (s nodeset) addAll(x nodeset) {
for label := range x {
s[label] = true
}
}
// A graph maps nodes to the non-nil set of their immediate successors.
type graph map[string]nodeset
func (g graph) addNode(label string) nodeset {
edges := g[label]
if edges == nil {
edges = make(nodeset)
g[label] = edges
}
return edges
}
func (g graph) addEdges(from string, to ...string) {
edges := g.addNode(from)
for _, to := range to {
g.addNode(to)
edges[to] = true
}
}
func (g graph) reachableFrom(roots nodeset) nodeset {
seen := make(nodeset)
var visit func(label string)
visit = func(label string) {
if !seen[label] {
seen[label] = true
for e := range g[label] {
visit(e)
}
}
}
for root := range roots {
visit(root)
}
return seen
}
func (g graph) transpose() graph {
rev := make(graph)
for label, edges := range g {
rev.addNode(label)
for succ := range edges {
rev.addEdges(succ, label)
}
}
return rev
}
func (g graph) sccs() []nodeset {
// Kosaraju's algorithm---Tarjan is overkill here.
// Forward pass.
S := make(nodelist, 0, len(g)) // postorder stack
seen := make(nodeset)
var visit func(label string)
visit = func(label string) {
if !seen[label] {
seen[label] = true
for e := range g[label] {
visit(e)
}
S = append(S, label)
}
}
for label := range g {
visit(label)
}
// Reverse pass.
rev := g.transpose()
var scc nodeset
seen = make(nodeset)
var rvisit func(label string)
rvisit = func(label string) {
if !seen[label] {
seen[label] = true
scc[label] = true
for e := range rev[label] {
rvisit(e)
}
}
}
var sccs []nodeset
for len(S) > 0 {
top := S[len(S)-1]
S = S[:len(S)-1] // pop
if !seen[top] {
scc = make(nodeset)
rvisit(top)
sccs = append(sccs, scc)
}
}
return sccs
}
func parse(rd io.Reader) (graph, error) {
g := make(graph)
var linenum int
in := bufio.NewScanner(rd)
for in.Scan() {
linenum++
// Split into words, honoring double-quotes per Go spec.
words, err := split(in.Text())
if err != nil {
return nil, fmt.Errorf("at line %d: %v", linenum, err)
}
if len(words) > 0 {
g.addEdges(words[0], words[1:]...)
}
}
if err := in.Err(); err != nil {
return nil, err
}
return g, nil
}
var stdin io.Reader = os.Stdin
var stdout io.Writer = os.Stdout
func digraph(cmd string, args []string) error {
// Parse the input graph.
g, err := parse(stdin)
if err != nil {
return err
}
// Parse the command line.
switch cmd {
case "nodes":
if len(args) != 0 {
return fmt.Errorf("usage: digraph nodes")
}
nodes := make(nodeset)
for label := range g {
nodes[label] = true
}
nodes.sort().println("\n")
case "degree":
if len(args) != 0 {
return fmt.Errorf("usage: digraph degree")
}
nodes := make(nodeset)
for label := range g {
nodes[label] = true
}
rev := g.transpose()
for _, label := range nodes.sort() {
fmt.Fprintf(stdout, "%d\t%d\t%s\n", len(rev[label]), len(g[label]), label)
}
case "succs", "preds":
if len(args) == 0 {
return fmt.Errorf("usage: digraph %s <label> ...", cmd)
}
g := g
if cmd == "preds" {
g = g.transpose()
}
result := make(nodeset)
for _, root := range args {
edges := g[root]
if edges == nil {
return fmt.Errorf("no such node %q", root)
}
result.addAll(edges)
}
result.sort().println("\n")
case "forward", "reverse":
if len(args) == 0 {
return fmt.Errorf("usage: digraph %s <label> ...", cmd)
}
roots := make(nodeset)
for _, root := range args {
if g[root] == nil {
return fmt.Errorf("no such node %q", root)
}
roots[root] = true
}
g := g
if cmd == "reverse" {
g = g.transpose()
}
g.reachableFrom(roots).sort().println("\n")
case "somepath":
if len(args) != 2 {
return fmt.Errorf("usage: digraph somepath <from> <to>")
}
from, to := args[0], args[1]
if g[from] == nil {
return fmt.Errorf("no such 'from' node %q", from)
}
if g[to] == nil {
return fmt.Errorf("no such 'to' node %q", to)
}
seen := make(nodeset)
var visit func(path nodelist, label string) bool
visit = func(path nodelist, label string) bool {
if !seen[label] {
seen[label] = true
if label == to {
append(path, label).println("\n")
return true // unwind
}
for e := range g[label] {
if visit(append(path, label), e) {
return true
}
}
}
return false
}
if !visit(make(nodelist, 0, 100), from) {
return fmt.Errorf("no path from %q to %q", args[0], args[1])
}
case "allpaths":
if len(args) != 2 {
return fmt.Errorf("usage: digraph allpaths <from> <to>")
}
from, to := args[0], args[1]
if g[from] == nil {
return fmt.Errorf("no such 'from' node %q", from)
}
if g[to] == nil {
return fmt.Errorf("no such 'to' node %q", to)
}
seen := make(nodeset) // value of seen[x] indicates whether x is on some path to 'to'
var visit func(label string) bool
visit = func(label string) bool {
reachesTo, ok := seen[label]
if !ok {
reachesTo = label == to
seen[label] = reachesTo
for e := range g[label] {
if visit(e) {
reachesTo = true
}
}
seen[label] = reachesTo
}
return reachesTo
}
if !visit(from) {
return fmt.Errorf("no path from %q to %q", from, to)
}
for label, reachesTo := range seen {
if !reachesTo {
delete(seen, label)
}
}
seen.sort().println("\n")
case "sccs":
if len(args) != 0 {
return fmt.Errorf("usage: digraph sccs")
}
for _, scc := range g.sccs() {
scc.sort().println(" ")
}
case "scc":
if len(args) != 1 {
return fmt.Errorf("usage: digraph scc <label>")
}
label := args[0]
if g[label] == nil {
return fmt.Errorf("no such node %q", label)
}
for _, scc := range g.sccs() {
if scc[label] {
scc.sort().println("\n")
break
}
}
default:
return fmt.Errorf("no such command %q", cmd)
}
return nil
}
// -- Utilities --------------------------------------------------------
// split splits a line into words, which are generally separated by
// spaces, but Go-style double-quoted string literals are also supported.
// (This approximates the behaviour of the Bourne shell.)
//
// `one "two three"` -> ["one" "two three"]
// `a"\n"b` -> ["a\nb"]
//
func split(line string) ([]string, error) {
var (
words []string
inWord bool
current bytes.Buffer
)
for len(line) > 0 {
r, size := utf8.DecodeRuneInString(line)
if unicode.IsSpace(r) {
if inWord {
words = append(words, current.String())
current.Reset()
inWord = false
}
} else if r == '"' {
var ok bool
size, ok = quotedLength(line)
if !ok {
return nil, errors.New("invalid quotation")
}
s, err := strconv.Unquote(line[:size])
if err != nil {
return nil, err
}
current.WriteString(s)
inWord = true
} else {
current.WriteRune(r)
inWord = true
}
line = line[size:]
}
if inWord {
words = append(words, current.String())
}
return words, nil
}
// quotedLength returns the length in bytes of the prefix of input that
// contain a possibly-valid double-quoted Go string literal.
//
// On success, n is at least two (""); input[:n] may be passed to
// strconv.Unquote to interpret its value, and input[n:] contains the
// rest of the input.
//
// On failure, quotedLength returns false, and the entire input can be
// passed to strconv.Unquote if an informative error message is desired.
//
// quotedLength does not and need not detect all errors, such as
// invalid hex or octal escape sequences, since it assumes
// strconv.Unquote will be applied to the prefix. It guarantees only
// that if there is a prefix of input containing a valid string literal,
// its length is returned.
//
// TODO(adonovan): move this into a strconv-like utility package.
//
func quotedLength(input string) (n int, ok bool) {
var offset int
// next returns the rune at offset, or -1 on EOF.
// offset advances to just after that rune.
next := func() rune {
if offset < len(input) {
r, size := utf8.DecodeRuneInString(input[offset:])
offset += size
return r
}
return -1
}
if next() != '"' {
return // error: not a quotation
}
for {
r := next()
if r == '\n' || r < 0 {
return // error: string literal not terminated
}
if r == '"' {
return offset, true // success
}
if r == '\\' {
var skip int
switch next() {
case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"':
skip = 0
case '0', '1', '2', '3', '4', '5', '6', '7':
skip = 2
case 'x':
skip = 2
case 'u':
skip = 4
case 'U':
skip = 8
default:
return // error: invalid escape
}
for i := 0; i < skip; i++ {
next()
}
}
}
}

121
vendor/golang.org/x/tools/cmd/digraph/digraph_test.go generated vendored Normal file
View File

@ -0,0 +1,121 @@
package main
import (
"bytes"
"fmt"
"reflect"
"strings"
"testing"
)
func TestDigraph(t *testing.T) {
const g1 = `
socks shoes
shorts pants
pants belt shoes
shirt tie sweater
sweater jacket
hat
`
const g2 = `
a b c
b d
c d
d c
`
for _, test := range []struct {
input string
cmd string
args []string
want string
}{
{g1, "nodes", nil, "belt\nhat\njacket\npants\nshirt\nshoes\nshorts\nsocks\nsweater\ntie\n"},
{g1, "reverse", []string{"jacket"}, "jacket\nshirt\nsweater\n"},
{g1, "forward", []string{"socks"}, "shoes\nsocks\n"},
{g1, "forward", []string{"socks", "sweater"}, "jacket\nshoes\nsocks\nsweater\n"},
{g2, "allpaths", []string{"a", "d"}, "a\nb\nc\nd\n"},
{g2, "sccs", nil, "a\nb\nc d\n"},
{g2, "scc", []string{"d"}, "c\nd\n"},
{g2, "succs", []string{"a"}, "b\nc\n"},
{g2, "preds", []string{"c"}, "a\nd\n"},
{g2, "preds", []string{"c", "d"}, "a\nb\nc\nd\n"},
} {
stdin = strings.NewReader(test.input)
stdout = new(bytes.Buffer)
if err := digraph(test.cmd, test.args); err != nil {
t.Error(err)
continue
}
got := stdout.(fmt.Stringer).String()
if got != test.want {
t.Errorf("digraph(%s, %s) = %q, want %q", test.cmd, test.args, got, test.want)
}
}
// TODO(adonovan):
// - test somepath (it's nondeterministic).
// - test errors
}
func TestSplit(t *testing.T) {
for _, test := range []struct {
line string
want []string
}{
{`one "2a 2b" three`, []string{"one", "2a 2b", "three"}},
{`one tw"\n\x0a\u000a\012"o three`, []string{"one", "tw\n\n\n\no", "three"}},
} {
got, err := split(test.line)
if err != nil {
t.Errorf("split(%s) failed: %v", test.line, err)
}
if !reflect.DeepEqual(got, test.want) {
t.Errorf("split(%s) = %v, want %v", test.line, got, test.want)
}
}
}
func TestQuotedLength(t *testing.T) {
for _, test := range []struct {
input string
want int
}{
{`"abc"`, 5},
{`"abc"def`, 5},
{`"abc\"d"ef`, 8}, // "abc\"d" is consumed, ef is residue
{`"\012\n\x0a\u000a\U0000000a"`, 28},
{"\"\xff\"", 3}, // bad UTF-8 is ok
{`"\xff"`, 6}, // hex escape for bad UTF-8 is ok
} {
got, ok := quotedLength(test.input)
if !ok {
got = 0
}
if got != test.want {
t.Errorf("quotedLength(%s) = %d, want %d", test.input, got, test.want)
}
}
// errors
for _, input := range []string{
``, // not a quotation
`a`, // not a quotation
`'a'`, // not a quotation
`"a`, // not terminated
`"\0"`, // short octal escape
`"\x1"`, // short hex escape
`"\u000"`, // short \u escape
`"\U0000000"`, // short \U escape
`"\k"`, // invalid escape
"\"ab\nc\"", // newline
} {
if n, ok := quotedLength(input); ok {
t.Errorf("quotedLength(%s) = %d, want !ok", input, n)
}
}
}

150
vendor/golang.org/x/tools/cmd/eg/eg.go generated vendored Normal file
View File

@ -0,0 +1,150 @@
// The eg command performs example-based refactoring.
// For documentation, run the command, or see Help in
// golang.org/x/tools/refactor/eg.
package main // import "golang.org/x/tools/cmd/eg"
import (
"flag"
"fmt"
"go/build"
"go/format"
"go/parser"
"go/token"
"os"
"os/exec"
"strings"
"golang.org/x/tools/go/buildutil"
"golang.org/x/tools/go/loader"
"golang.org/x/tools/refactor/eg"
)
var (
beforeeditFlag = flag.String("beforeedit", "", "A command to exec before each file is edited (e.g. chmod, checkout). Whitespace delimits argument words. The string '{}' is replaced by the file name.")
helpFlag = flag.Bool("help", false, "show detailed help message")
templateFlag = flag.String("t", "", "template.go file specifying the refactoring")
transitiveFlag = flag.Bool("transitive", false, "apply refactoring to all dependencies too")
writeFlag = flag.Bool("w", false, "rewrite input files in place (by default, the results are printed to standard output)")
verboseFlag = flag.Bool("v", false, "show verbose matcher diagnostics")
)
func init() {
flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
}
const usage = `eg: an example-based refactoring tool.
Usage: eg -t template.go [-w] [-transitive] <args>...
-help show detailed help message
-t template.go specifies the template file (use -help to see explanation)
-w causes files to be re-written in place.
-transitive causes all dependencies to be refactored too.
-v show verbose matcher diagnostics
-beforeedit cmd a command to exec before each file is modified.
"{}" represents the name of the file.
` + loader.FromArgsUsage
func main() {
if err := doMain(); err != nil {
fmt.Fprintf(os.Stderr, "eg: %s\n", err)
os.Exit(1)
}
}
func doMain() error {
flag.Parse()
args := flag.Args()
if *helpFlag {
fmt.Fprint(os.Stderr, eg.Help)
os.Exit(2)
}
if len(args) == 0 {
fmt.Fprint(os.Stderr, usage)
os.Exit(1)
}
if *templateFlag == "" {
return fmt.Errorf("no -t template.go file specified")
}
conf := loader.Config{
Fset: token.NewFileSet(),
ParserMode: parser.ParseComments,
}
// The first Created package is the template.
conf.CreateFromFilenames("template", *templateFlag)
if _, err := conf.FromArgs(args, true); err != nil {
return err
}
// Load, parse and type-check the whole program.
iprog, err := conf.Load()
if err != nil {
return err
}
// Analyze the template.
template := iprog.Created[0]
xform, err := eg.NewTransformer(iprog.Fset, template.Pkg, template.Files[0], &template.Info, *verboseFlag)
if err != nil {
return err
}
// Apply it to the input packages.
var pkgs []*loader.PackageInfo
if *transitiveFlag {
for _, info := range iprog.AllPackages {
pkgs = append(pkgs, info)
}
} else {
pkgs = iprog.InitialPackages()
}
var hadErrors bool
for _, pkg := range pkgs {
if pkg == template {
continue
}
for _, file := range pkg.Files {
n := xform.Transform(&pkg.Info, pkg.Pkg, file)
if n == 0 {
continue
}
filename := iprog.Fset.File(file.Pos()).Name()
fmt.Fprintf(os.Stderr, "=== %s (%d matches)\n", filename, n)
if *writeFlag {
// Run the before-edit command (e.g. "chmod +w", "checkout") if any.
if *beforeeditFlag != "" {
args := strings.Fields(*beforeeditFlag)
// Replace "{}" with the filename, like find(1).
for i := range args {
if i > 0 {
args[i] = strings.Replace(args[i], "{}", filename, -1)
}
}
cmd := exec.Command(args[0], args[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
fmt.Fprintf(os.Stderr, "Warning: edit hook %q failed (%s)\n",
args, err)
}
}
if err := eg.WriteAST(iprog.Fset, filename, file); err != nil {
fmt.Fprintf(os.Stderr, "eg: %s\n", err)
hadErrors = true
}
} else {
format.Node(os.Stdout, iprog.Fset, file)
}
}
}
if hadErrors {
os.Exit(1)
}
return nil
}

511
vendor/golang.org/x/tools/cmd/fiximports/main.go generated vendored Normal file
View File

@ -0,0 +1,511 @@
// 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.
// The fiximports command fixes import declarations to use the canonical
// import path for packages that have an "import comment" as defined by
// https://golang.org/s/go14customimport.
//
//
// Background
//
// The Go 1 custom import path mechanism lets the maintainer of a
// package give it a stable name by which clients may import and "go
// get" it, independent of the underlying version control system (such
// as Git) or server (such as github.com) that hosts it. Requests for
// the custom name are redirected to the underlying name. This allows
// packages to be migrated from one underlying server or system to
// another without breaking existing clients.
//
// Because this redirect mechanism creates aliases for existing
// packages, it's possible for a single program to import the same
// package by its canonical name and by an alias. The resulting
// executable will contain two copies of the package, which is wasteful
// at best and incorrect at worst.
//
// To avoid this, "go build" reports an error if it encounters a special
// comment like the one below, and if the import path in the comment
// does not match the path of the enclosing package relative to
// GOPATH/src:
//
// $ grep ^package $GOPATH/src/github.com/bob/vanity/foo/foo.go
// package foo // import "vanity.com/foo"
//
// The error from "go build" indicates that the package canonically
// known as "vanity.com/foo" is locally installed under the
// non-canonical name "github.com/bob/vanity/foo".
//
//
// Usage
//
// When a package that you depend on introduces a custom import comment,
// and your workspace imports it by the non-canonical name, your build
// will stop working as soon as you update your copy of that package
// using "go get -u".
//
// The purpose of the fiximports tool is to fix up all imports of the
// non-canonical path within a Go workspace, replacing them with imports
// of the canonical path. Following a run of fiximports, the workspace
// will no longer depend on the non-canonical copy of the package, so it
// should be safe to delete. It may be necessary to run "go get -u"
// again to ensure that the package is locally installed under its
// canonical path, if it was not already.
//
// The fiximports tool operates locally; it does not make HTTP requests
// and does not discover new custom import comments. It only operates
// on non-canonical packages present in your workspace.
//
// The -baddomains flag is a list of domain names that should always be
// considered non-canonical. You can use this if you wish to make sure
// that you no longer have any dependencies on packages from that
// domain, even those that do not yet provide a canical import path
// comment. For example, the default value of -baddomains includes the
// moribund code hosting site code.google.com, so fiximports will report
// an error for each import of a package from this domain remaining
// after canonicalization.
//
// To see the changes fiximports would make without applying them, use
// the -n flag.
//
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"go/ast"
"go/build"
"go/format"
"go/parser"
"go/token"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"sort"
"strconv"
"strings"
)
// flags
var (
dryrun = flag.Bool("n", false, "dry run: show changes, but don't apply them")
badDomains = flag.String("baddomains", "code.google.com",
"a comma-separated list of domains from which packages should not be imported")
replaceFlag = flag.String("replace", "",
"a comma-separated list of noncanonical=canonical pairs of package paths. If both items in a pair end with '...', they are treated as path prefixes.")
)
// seams for testing
var (
stderr io.Writer = os.Stderr
writeFile = ioutil.WriteFile
)
const usage = `fiximports: rewrite import paths to use canonical package names.
Usage: fiximports [-n] package...
The package... arguments specify a list of packages
in the style of the go tool; see "go help packages".
Hint: use "all" or "..." to match the entire workspace.
For details, see http://godoc.org/golang.org/x/tools/cmd/fiximports.
Flags:
-n: dry run: show changes, but don't apply them
-baddomains a comma-separated list of domains from which packages
should not be imported
`
func main() {
flag.Parse()
if len(flag.Args()) == 0 {
fmt.Fprintf(stderr, usage)
os.Exit(1)
}
if !fiximports(flag.Args()...) {
os.Exit(1)
}
}
type canonicalName struct{ path, name string }
// fiximports fixes imports in the specified packages.
// Invariant: a false result implies an error was already printed.
func fiximports(packages ...string) bool {
// importedBy is the transpose of the package import graph.
importedBy := make(map[string]map[*build.Package]bool)
// addEdge adds an edge to the import graph.
addEdge := func(from *build.Package, to string) {
if to == "C" || to == "unsafe" {
return // fake
}
pkgs := importedBy[to]
if pkgs == nil {
pkgs = make(map[*build.Package]bool)
importedBy[to] = pkgs
}
pkgs[from] = true
}
// List metadata for all packages in the workspace.
pkgs, err := list("...")
if err != nil {
fmt.Fprintf(stderr, "importfix: %v\n", err)
return false
}
// packageName maps each package's path to its name.
packageName := make(map[string]string)
for _, p := range pkgs {
packageName[p.ImportPath] = p.Package.Name
}
// canonical maps each non-canonical package path to
// its canonical path and name.
// A present nil value indicates that the canonical package
// is unknown: hosted on a bad domain with no redirect.
canonical := make(map[string]canonicalName)
domains := strings.Split(*badDomains, ",")
type replaceItem struct {
old, new string
matchPrefix bool
}
var replace []replaceItem
for _, pair := range strings.Split(*replaceFlag, ",") {
if pair == "" {
continue
}
words := strings.Split(pair, "=")
if len(words) != 2 {
fmt.Fprintf(stderr, "importfix: -replace: %q is not of the form \"canonical=noncanonical\".\n", pair)
return false
}
replace = append(replace, replaceItem{
old: strings.TrimSuffix(words[0], "..."),
new: strings.TrimSuffix(words[1], "..."),
matchPrefix: strings.HasSuffix(words[0], "...") &&
strings.HasSuffix(words[1], "..."),
})
}
// Find non-canonical packages and populate importedBy graph.
for _, p := range pkgs {
if p.Error != nil {
msg := p.Error.Err
if strings.Contains(msg, "code in directory") &&
strings.Contains(msg, "expects import") {
// don't show the very errors we're trying to fix
} else {
fmt.Fprintln(stderr, msg)
}
}
for _, imp := range p.Imports {
addEdge(&p.Package, imp)
}
for _, imp := range p.TestImports {
addEdge(&p.Package, imp)
}
for _, imp := range p.XTestImports {
addEdge(&p.Package, imp)
}
// Does package have an explicit import comment?
if p.ImportComment != "" {
if p.ImportComment != p.ImportPath {
canonical[p.ImportPath] = canonicalName{
path: p.Package.ImportComment,
name: p.Package.Name,
}
}
} else {
// Is package matched by a -replace item?
var newPath string
for _, item := range replace {
if item.matchPrefix {
if strings.HasPrefix(p.ImportPath, item.old) {
newPath = item.new + p.ImportPath[len(item.old):]
break
}
} else if p.ImportPath == item.old {
newPath = item.new
break
}
}
if newPath != "" {
newName := packageName[newPath]
if newName == "" {
newName = filepath.Base(newPath) // a guess
}
canonical[p.ImportPath] = canonicalName{
path: newPath,
name: newName,
}
continue
}
// Is package matched by a -baddomains item?
for _, domain := range domains {
slash := strings.Index(p.ImportPath, "/")
if slash < 0 {
continue // no slash: standard package
}
if p.ImportPath[:slash] == domain {
// Package comes from bad domain and has no import comment.
// Report an error each time this package is imported.
canonical[p.ImportPath] = canonicalName{}
// TODO(adonovan): should we make an HTTP request to
// see if there's an HTTP redirect, a "go-import" meta tag,
// or an import comment in the the latest revision?
// It would duplicate a lot of logic from "go get".
}
break
}
}
}
// Find all clients (direct importers) of canonical packages.
// These are the packages that need fixing up.
clients := make(map[*build.Package]bool)
for path := range canonical {
for client := range importedBy[path] {
clients[client] = true
}
}
// Restrict rewrites to the set of packages specified by the user.
if len(packages) == 1 && (packages[0] == "all" || packages[0] == "...") {
// no restriction
} else {
pkgs, err := list(packages...)
if err != nil {
fmt.Fprintf(stderr, "importfix: %v\n", err)
return false
}
seen := make(map[string]bool)
for _, p := range pkgs {
seen[p.ImportPath] = true
}
for client := range clients {
if !seen[client.ImportPath] {
delete(clients, client)
}
}
}
// Rewrite selected client packages.
ok := true
for client := range clients {
if !rewritePackage(client, canonical) {
ok = false
// There were errors.
// Show direct and indirect imports of client.
seen := make(map[string]bool)
var direct, indirect []string
for p := range importedBy[client.ImportPath] {
direct = append(direct, p.ImportPath)
seen[p.ImportPath] = true
}
var visit func(path string)
visit = func(path string) {
for q := range importedBy[path] {
qpath := q.ImportPath
if !seen[qpath] {
seen[qpath] = true
indirect = append(indirect, qpath)
visit(qpath)
}
}
}
if direct != nil {
fmt.Fprintf(stderr, "\timported directly by:\n")
sort.Strings(direct)
for _, path := range direct {
fmt.Fprintf(stderr, "\t\t%s\n", path)
visit(path)
}
if indirect != nil {
fmt.Fprintf(stderr, "\timported indirectly by:\n")
sort.Strings(indirect)
for _, path := range indirect {
fmt.Fprintf(stderr, "\t\t%s\n", path)
}
}
}
}
}
return ok
}
// Invariant: false result => error already printed.
func rewritePackage(client *build.Package, canonical map[string]canonicalName) bool {
ok := true
used := make(map[string]bool)
var filenames []string
filenames = append(filenames, client.GoFiles...)
filenames = append(filenames, client.TestGoFiles...)
filenames = append(filenames, client.XTestGoFiles...)
var first bool
for _, filename := range filenames {
if !first {
first = true
fmt.Fprintf(stderr, "%s\n", client.ImportPath)
}
err := rewriteFile(filepath.Join(client.Dir, filename), canonical, used)
if err != nil {
fmt.Fprintf(stderr, "\tERROR: %v\n", err)
ok = false
}
}
// Show which imports were renamed in this package.
var keys []string
for key := range used {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
if p := canonical[key]; p.path != "" {
fmt.Fprintf(stderr, "\tfixed: %s -> %s\n", key, p.path)
} else {
fmt.Fprintf(stderr, "\tERROR: %s has no import comment\n", key)
ok = false
}
}
return ok
}
// rewrite reads, modifies, and writes filename, replacing all imports
// of packages P in canonical by canonical[P].
// It records in used which canonical packages were imported.
// used[P]=="" indicates that P was imported but its canonical path is unknown.
func rewriteFile(filename string, canonical map[string]canonicalName, used map[string]bool) error {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
if err != nil {
return err
}
var changed bool
for _, imp := range f.Imports {
impPath, err := strconv.Unquote(imp.Path.Value)
if err != nil {
log.Printf("%s: bad import spec %q: %v",
fset.Position(imp.Pos()), imp.Path.Value, err)
continue
}
canon, ok := canonical[impPath]
if !ok {
continue // import path is canonical
}
used[impPath] = true
if canon.path == "" {
// The canonical path is unknown (a -baddomain).
// Show the offending import.
// TODO(adonovan): should we show the actual source text?
fmt.Fprintf(stderr, "\t%s:%d: import %q\n",
shortPath(filename),
fset.Position(imp.Pos()).Line, impPath)
continue
}
changed = true
imp.Path.Value = strconv.Quote(canon.path)
// Add a renaming import if necessary.
//
// This is a guess at best. We can't see whether a 'go
// get' of the canonical import path would have the same
// name or not. Assume it's the last segment.
newBase := path.Base(canon.path)
if imp.Name == nil && newBase != canon.name {
imp.Name = &ast.Ident{Name: canon.name}
}
}
if changed && !*dryrun {
var buf bytes.Buffer
if err := format.Node(&buf, fset, f); err != nil {
return fmt.Errorf("%s: couldn't format file: %v", filename, err)
}
return writeFile(filename, buf.Bytes(), 0644)
}
return nil
}
// listPackage is a copy of cmd/go/list.Package.
// It has more fields than build.Package and we need some of them.
type listPackage struct {
build.Package
Error *packageError // error loading package
}
// A packageError describes an error loading information about a package.
type packageError struct {
ImportStack []string // shortest path from package named on command line to this one
Pos string // position of error
Err string // the error itself
}
// list runs 'go list' with the specified arguments and returns the
// metadata for matching packages.
func list(args ...string) ([]*listPackage, error) {
cmd := exec.Command("go", append([]string{"list", "-e", "-json"}, args...)...)
cmd.Stdout = new(bytes.Buffer)
cmd.Stderr = stderr
if err := cmd.Run(); err != nil {
return nil, err
}
dec := json.NewDecoder(cmd.Stdout.(io.Reader))
var pkgs []*listPackage
for {
var p listPackage
if err := dec.Decode(&p); err == io.EOF {
break
} else if err != nil {
return nil, err
}
pkgs = append(pkgs, &p)
}
return pkgs, nil
}
var cwd string
func init() {
var err error
cwd, err = os.Getwd()
if err != nil {
log.Fatalf("os.Getwd: %v", err)
}
}
// shortPath returns an absolute or relative name for path, whatever is shorter.
// Plundered from $GOROOT/src/cmd/go/build.go.
func shortPath(path string) string {
if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
return rel
}
return path
}

243
vendor/golang.org/x/tools/cmd/fiximports/main_test.go generated vendored Normal file
View File

@ -0,0 +1,243 @@
// 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.
// No testdata on Android.
// +build !android
package main
import (
"bytes"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
// TODO(adonovan):
// - test introduction of renaming imports.
// - test induced failures of rewriteFile.
// Guide to the test packages:
//
// new.com/one -- canonical name for old.com/one
// old.com/one -- non-canonical; has import comment "new.com/one"
// old.com/bad -- has a parse error
// fruit.io/orange \
// fruit.io/banana } orange -> pear -> banana -> titanic.biz/bar
// fruit.io/pear /
// titanic.biz/bar -- domain is sinking; package has jumped ship to new.com/bar
// titanic.biz/foo -- domain is sinking but package has no import comment yet
func TestFixImports(t *testing.T) {
gopath := filepath.Join(cwd, "testdata")
if err := os.Setenv("GOPATH", gopath); err != nil {
t.Fatalf("os.Setenv: %v", err)
}
defer func() {
stderr = os.Stderr
*badDomains = "code.google.com"
*replaceFlag = ""
}()
for i, test := range []struct {
packages []string // packages to rewrite, "go list" syntax
badDomains string // -baddomains flag
replaceFlag string // -replace flag
wantOK bool
wantStderr string
wantRewrite map[string]string
}{
// #0. No errors.
{
packages: []string{"all"},
badDomains: "code.google.com",
wantOK: true,
wantStderr: `
testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
fruit.io/banana
fixed: old.com/one -> new.com/one
fixed: titanic.biz/bar -> new.com/bar
`,
wantRewrite: map[string]string{
"$GOPATH/src/fruit.io/banana/banana.go": `package banana
import (
_ "new.com/bar"
_ "new.com/one"
_ "titanic.biz/foo"
)`,
},
},
// #1. No packages needed rewriting.
{
packages: []string{"titanic.biz/...", "old.com/...", "new.com/..."},
badDomains: "code.google.com",
wantOK: true,
wantStderr: `
testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
`,
},
// #2. Some packages without import comments matched bad domains.
{
packages: []string{"all"},
badDomains: "titanic.biz",
wantOK: false,
wantStderr: `
testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
fruit.io/banana
testdata/src/fruit.io/banana/banana.go:6: import "titanic.biz/foo"
fixed: old.com/one -> new.com/one
fixed: titanic.biz/bar -> new.com/bar
ERROR: titanic.biz/foo has no import comment
imported directly by:
fruit.io/pear
imported indirectly by:
fruit.io/orange
`,
wantRewrite: map[string]string{
"$GOPATH/src/fruit.io/banana/banana.go": `package banana
import (
_ "new.com/bar"
_ "new.com/one"
_ "titanic.biz/foo"
)`,
},
},
// #3. The -replace flag lets user supply missing import comments.
{
packages: []string{"all"},
replaceFlag: "titanic.biz/foo=new.com/foo",
wantOK: true,
wantStderr: `
testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
fruit.io/banana
fixed: old.com/one -> new.com/one
fixed: titanic.biz/bar -> new.com/bar
fixed: titanic.biz/foo -> new.com/foo
`,
wantRewrite: map[string]string{
"$GOPATH/src/fruit.io/banana/banana.go": `package banana
import (
_ "new.com/bar"
_ "new.com/foo"
_ "new.com/one"
)`,
},
},
// #4. The -replace flag supports wildcards.
// An explicit import comment takes precedence.
{
packages: []string{"all"},
replaceFlag: "titanic.biz/...=new.com/...",
wantOK: true,
wantStderr: `
testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
fruit.io/banana
fixed: old.com/one -> new.com/one
fixed: titanic.biz/bar -> new.com/bar
fixed: titanic.biz/foo -> new.com/foo
`,
wantRewrite: map[string]string{
"$GOPATH/src/fruit.io/banana/banana.go": `package banana
import (
_ "new.com/bar"
_ "new.com/foo"
_ "new.com/one"
)`,
},
},
// #5. The -replace flag trumps -baddomains.
{
packages: []string{"all"},
badDomains: "titanic.biz",
replaceFlag: "titanic.biz/foo=new.com/foo",
wantOK: true,
wantStderr: `
testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
fruit.io/banana
fixed: old.com/one -> new.com/one
fixed: titanic.biz/bar -> new.com/bar
fixed: titanic.biz/foo -> new.com/foo
`,
wantRewrite: map[string]string{
"$GOPATH/src/fruit.io/banana/banana.go": `package banana
import (
_ "new.com/bar"
_ "new.com/foo"
_ "new.com/one"
)`,
},
},
} {
*badDomains = test.badDomains
*replaceFlag = test.replaceFlag
stderr = new(bytes.Buffer)
gotRewrite := make(map[string]string)
writeFile = func(filename string, content []byte, mode os.FileMode) error {
filename = strings.Replace(filename, gopath, "$GOPATH", 1)
filename = filepath.ToSlash(filename)
gotRewrite[filename] = string(bytes.TrimSpace(content))
return nil
}
if runtime.GOOS == "windows" {
test.wantStderr = strings.Replace(test.wantStderr, `testdata/src/old.com/bad/bad.go`, `testdata\src\old.com\bad\bad.go`, -1)
test.wantStderr = strings.Replace(test.wantStderr, `testdata/src/fruit.io/banana/banana.go`, `testdata\src\fruit.io\banana\banana.go`, -1)
}
// Check status code.
if fiximports(test.packages...) != test.wantOK {
t.Errorf("#%d. fiximports() = %t", i, !test.wantOK)
}
// Compare stderr output.
if got := stderr.(*bytes.Buffer).String(); got != test.wantStderr {
if strings.Contains(got, "vendor/golang_org/x/text/unicode/norm") {
t.Skip("skipping known-broken test; see golang.org/issue/17417")
}
t.Errorf("#%d. stderr: got <<%s>>, want <<%s>>",
i, stderr, test.wantStderr)
}
// Compare rewrites.
for k, v := range gotRewrite {
if test.wantRewrite[k] != v {
t.Errorf("#%d. rewrite[%s] = <<%s>>, want <<%s>>",
i, k, v, test.wantRewrite[k])
}
delete(test.wantRewrite, k)
}
for k, v := range test.wantRewrite {
t.Errorf("#%d. rewrite[%s] missing, want <<%s>>", i, k, v)
}
}
}
// TestDryRun tests that the -n flag suppresses calls to writeFile.
func TestDryRun(t *testing.T) {
gopath := filepath.Join(cwd, "testdata")
if err := os.Setenv("GOPATH", gopath); err != nil {
t.Fatalf("os.Setenv: %v", err)
}
*dryrun = true
defer func() { *dryrun = false }() // restore
stderr = new(bytes.Buffer)
writeFile = func(filename string, content []byte, mode os.FileMode) error {
t.Fatalf("writeFile(%s) called in dryrun mode", filename)
return nil
}
if !fiximports("all") {
t.Fatalf("fiximports failed: %s", stderr)
}
}

View File

@ -0,0 +1,7 @@
package banana
import (
_ "old.com/one"
_ "titanic.biz/bar"
_ "titanic.biz/foo"
)

View File

@ -0,0 +1,3 @@
package orange
import _ "fruit.io/pear"

View File

@ -0,0 +1,3 @@
package pear
import _ "fruit.io/banana"

View File

@ -0,0 +1 @@
package one // import "new.com/one"

View File

@ -0,0 +1,2 @@
// This ill-formed Go source file is here to ensure the tool is robust
// against bad packages in the workspace.

View File

@ -0,0 +1 @@
package one // import "new.com/one"

View File

@ -0,0 +1,2 @@
// This package is moving to new.com too.
package bar // import "new.com/bar"

View File

@ -0,0 +1,2 @@
// This package hasn't jumped ship yet.
package foo

5
vendor/golang.org/x/tools/cmd/getgo/.dockerignore generated vendored Normal file
View File

@ -0,0 +1,5 @@
.git
.dockerignore
LICENSE
README.md
.gitignore

3
vendor/golang.org/x/tools/cmd/getgo/.gitignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
build
testgetgo
getgo

20
vendor/golang.org/x/tools/cmd/getgo/Dockerfile generated vendored Normal file
View File

@ -0,0 +1,20 @@
FROM golang:latest
ENV SHELL /bin/bash
ENV HOME /root
WORKDIR $HOME
COPY . /go/src/golang.org/x/tools/cmd/getgo
RUN ( \
cd /go/src/golang.org/x/tools/cmd/getgo \
&& go build \
&& mv getgo /usr/local/bin/getgo \
)
# undo the adding of GOPATH to env for testing
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ENV GOPATH ""
# delete /go and /usr/local/go for testing
RUN rm -rf /go /usr/local/go

27
vendor/golang.org/x/tools/cmd/getgo/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2017 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

71
vendor/golang.org/x/tools/cmd/getgo/README.md generated vendored Normal file
View File

@ -0,0 +1,71 @@
# getgo
A proof-of-concept command-line installer for Go.
This installer is designed to both install Go as well as do the initial configuration
of setting up the right environment variables and paths.
It will install the Go distribution (tools & stdlib) to "/.go" inside your home directory by default.
It will setup "$HOME/go" as your GOPATH.
This is where third party libraries and apps will be installed as well as where you will write your Go code.
If Go is already installed via this installer it will upgrade it to the latest version of Go.
Currently the installer supports Windows, \*nix and macOS on x86 & x64.
It supports Bash and Zsh on all of these platforms as well as powershell & cmd.exe on Windows.
## Usage
Windows Powershell/cmd.exe:
`(New-Object System.Net.WebClient).DownloadFile('https://get.golang.org/installer.exe', 'installer.exe'); Start-Process -Wait -NonewWindow installer.exe; Remove-Item installer.exe`
Shell (Linux/macOS/Windows):
`curl -LO https://get.golang.org/$(uname)/go_installer && chmod +x go_installer && ./go_installer && rm go_installer`
## To Do
* Check if Go is already installed (via a different method) and update it in place or at least notify the user
* Lots of testing. It's only had limited testing so far.
* Add support for additional shells.
## Development instructions
### Testing
There are integration tests in [`main_test.go`](main_test.go). Please add more
tests there.
#### On unix/linux with the Dockerfile
The Dockerfile automatically builds the binary, moves it to
`/usr/local/bin/getgo` and then unsets `$GOPATH` and removes all `$GOPATH` from
`$PATH`.
```bash
$ docker build --rm --force-rm -t getgo .
...
$ docker run --rm -it getgo bash
root@78425260fad0:~# getgo -v
Welcome to the Go installer!
Downloading Go version go1.8.3 to /usr/local/go
This may take a bit of time...
Adding "export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin" to /root/.bashrc
Downloaded!
Setting up GOPATH
Adding "export GOPATH=/root/go" to /root/.bashrc
Adding "export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/root/go/bin" to /root/.bashrc
GOPATH has been setup!
root@78425260fad0:~# which go
/usr/local/go/bin/go
root@78425260fad0:~# echo $GOPATH
/root/go
root@78425260fad0:~# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/root/go/bin
```
## Release instructions
To upload a new release of getgo, run `./make.bash && ./upload.bash`.

184
vendor/golang.org/x/tools/cmd/getgo/download.go generated vendored Normal file
View File

@ -0,0 +1,184 @@
// 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 !plan9
package main
import (
"archive/tar"
"archive/zip"
"compress/gzip"
"crypto/sha256"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strings"
)
const (
currentVersionURL = "https://golang.org/VERSION?m=text"
downloadURLPrefix = "https://dl.google.com/go"
)
// downloadGoVersion downloads and upacks the specific go version to dest/go.
func downloadGoVersion(version, ops, arch, dest string) error {
suffix := "tar.gz"
if ops == "windows" {
suffix = "zip"
}
uri := fmt.Sprintf("%s/%s.%s-%s.%s", downloadURLPrefix, version, ops, arch, suffix)
verbosef("Downloading %s", uri)
req, err := http.NewRequest("GET", uri, nil)
if err != nil {
return err
}
req.Header.Add("User-Agent", fmt.Sprintf("golang.org-getgo/%s", version))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("Downloading Go from %s failed: %v", uri, err)
}
if resp.StatusCode > 299 {
return fmt.Errorf("Downloading Go from %s failed with HTTP status %s", uri, resp.Status)
}
defer resp.Body.Close()
tmpf, err := ioutil.TempFile("", "go")
if err != nil {
return err
}
defer os.Remove(tmpf.Name())
h := sha256.New()
w := io.MultiWriter(tmpf, h)
if _, err := io.Copy(w, resp.Body); err != nil {
return err
}
verbosef("Downloading SHA %s.sha256", uri)
sresp, err := http.Get(uri + ".sha256")
if err != nil {
return fmt.Errorf("Downloading Go sha256 from %s.sha256 failed: %v", uri, err)
}
defer sresp.Body.Close()
if sresp.StatusCode > 299 {
return fmt.Errorf("Downloading Go sha256 from %s.sha256 failed with HTTP status %s", uri, sresp.Status)
}
shasum, err := ioutil.ReadAll(sresp.Body)
if err != nil {
return err
}
// Check the shasum.
sum := fmt.Sprintf("%x", h.Sum(nil))
if sum != string(shasum) {
return fmt.Errorf("Shasum mismatch %s vs. %s", sum, string(shasum))
}
unpackFunc := unpackTar
if ops == "windows" {
unpackFunc = unpackZip
}
if err := unpackFunc(tmpf.Name(), dest); err != nil {
return fmt.Errorf("Unpacking Go to %s failed: %v", dest, err)
}
return nil
}
func unpack(dest, name string, fi os.FileInfo, r io.Reader) error {
if strings.HasPrefix(name, "go/") {
name = name[len("go/"):]
}
path := filepath.Join(dest, name)
if fi.IsDir() {
return os.MkdirAll(path, fi.Mode())
}
f, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fi.Mode())
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, r)
return err
}
func unpackTar(src, dest string) error {
r, err := os.Open(src)
if err != nil {
return err
}
defer r.Close()
archive, err := gzip.NewReader(r)
if err != nil {
return err
}
defer archive.Close()
tarReader := tar.NewReader(archive)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
} else if err != nil {
return err
}
if err := unpack(dest, header.Name, header.FileInfo(), tarReader); err != nil {
return err
}
}
return nil
}
func unpackZip(src, dest string) error {
zr, err := zip.OpenReader(src)
if err != nil {
return err
}
for _, f := range zr.File {
fr, err := f.Open()
if err != nil {
return err
}
if err := unpack(dest, f.Name, f.FileInfo(), fr); err != nil {
return err
}
fr.Close()
}
return nil
}
func getLatestGoVersion() (string, error) {
resp, err := http.Get(currentVersionURL)
if err != nil {
return "", fmt.Errorf("Getting current Go version failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode > 299 {
b, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 1024))
return "", fmt.Errorf("Could not get current Go version: HTTP %d: %q", resp.StatusCode, b)
}
version, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return strings.TrimSpace(string(version)), nil
}

36
vendor/golang.org/x/tools/cmd/getgo/download_test.go generated vendored Normal file
View File

@ -0,0 +1,36 @@
// 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 !plan9
package main
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
)
func TestDownloadGoVersion(t *testing.T) {
if testing.Short() {
t.Skipf("Skipping download in short mode")
}
tmpd, err := ioutil.TempDir("", "go")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpd)
if err := downloadGoVersion("go1.8.1", "linux", "amd64", filepath.Join(tmpd, "go")); err != nil {
t.Fatal(err)
}
// Ensure the VERSION file exists.
vf := filepath.Join(tmpd, "go", "VERSION")
if _, err := os.Stat(vf); os.IsNotExist(err) {
t.Fatalf("file %s does not exist and should", vf)
}
}

117
vendor/golang.org/x/tools/cmd/getgo/main.go generated vendored Normal file
View File

@ -0,0 +1,117 @@
// 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 !plan9
// The getgo command installs Go to the user's system.
package main
import (
"bufio"
"context"
"errors"
"flag"
"fmt"
"os"
"os/exec"
"strings"
)
var (
interactive = flag.Bool("i", false, "Interactive mode, prompt for inputs.")
verbose = flag.Bool("v", false, "Verbose.")
setupOnly = flag.Bool("skip-dl", false, "Don't download - only set up environment variables")
goVersion = flag.String("version", "", `Version of Go to install (e.g. "1.8.3"). If empty, uses the latest version.`)
version = "devel"
)
var exitCleanly error = errors.New("exit cleanly sentinel value")
func main() {
flag.Parse()
if *goVersion != "" && !strings.HasPrefix(*goVersion, "go") {
*goVersion = "go" + *goVersion
}
ctx := context.Background()
verbosef("version " + version)
runStep := func(s step) {
err := s(ctx)
if err == exitCleanly {
os.Exit(0)
}
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
}
if !*setupOnly {
runStep(welcome)
runStep(checkOthers)
runStep(chooseVersion)
runStep(downloadGo)
}
runStep(setupGOPATH)
}
func verbosef(format string, v ...interface{}) {
if !*verbose {
return
}
fmt.Printf(format+"\n", v...)
}
func prompt(ctx context.Context, query, defaultAnswer string) (string, error) {
if !*interactive {
return defaultAnswer, nil
}
fmt.Printf("%s [%s]: ", query, defaultAnswer)
type result struct {
answer string
err error
}
ch := make(chan result, 1)
go func() {
s := bufio.NewScanner(os.Stdin)
if !s.Scan() {
ch <- result{"", s.Err()}
return
}
answer := s.Text()
if answer == "" {
answer = defaultAnswer
}
ch <- result{answer, nil}
}()
select {
case r := <-ch:
return r.answer, r.err
case <-ctx.Done():
return "", ctx.Err()
}
}
func runCommand(ctx context.Context, prog string, args ...string) ([]byte, error) {
verbosef("Running command: %s %v", prog, args)
cmd := exec.CommandContext(ctx, prog, args...)
out, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("running cmd '%s %s' failed: %s err: %v", prog, strings.Join(args, " "), string(out), err)
}
if out != nil && err == nil && len(out) != 0 {
verbosef("%s", out)
}
return out, nil
}

173
vendor/golang.org/x/tools/cmd/getgo/main_test.go generated vendored Normal file
View File

@ -0,0 +1,173 @@
// 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 !plan9
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"runtime"
"testing"
)
const (
testbin = "testgetgo"
)
var (
exeSuffix string // ".exe" on Windows
)
func init() {
if runtime.GOOS == "windows" {
exeSuffix = ".exe"
}
}
// TestMain creates a getgo command for testing purposes and
// deletes it after the tests have been run.
func TestMain(m *testing.M) {
if os.Getenv("GOGET_INTEGRATION") == "" {
fmt.Fprintln(os.Stderr, "main_test: Skipping integration tests with GOGET_INTEGRATION unset")
return
}
args := []string{"build", "-tags", testbin, "-o", testbin + exeSuffix}
out, err := exec.Command("go", args...).CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "building %s failed: %v\n%s", testbin, err, out)
os.Exit(2)
}
// Don't let these environment variables confuse the test.
os.Unsetenv("GOBIN")
os.Unsetenv("GOPATH")
os.Unsetenv("GIT_ALLOW_PROTOCOL")
os.Unsetenv("PATH")
r := m.Run()
os.Remove(testbin + exeSuffix)
os.Exit(r)
}
func createTmpHome(t *testing.T) string {
tmpd, err := ioutil.TempDir("", "testgetgo")
if err != nil {
t.Fatalf("creating test tempdir failed: %v", err)
}
os.Setenv("HOME", tmpd)
return tmpd
}
// doRun runs the test getgo command, recording stdout and stderr and
// returning exit status.
func doRun(t *testing.T, args ...string) error {
var stdout, stderr bytes.Buffer
t.Logf("running %s %v", testbin, args)
cmd := exec.Command("./"+testbin+exeSuffix, args...)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
cmd.Env = os.Environ()
status := cmd.Run()
if stdout.Len() > 0 {
t.Log("standard output:")
t.Log(stdout.String())
}
if stderr.Len() > 0 {
t.Log("standard error:")
t.Log(stderr.String())
}
return status
}
func TestCommandVerbose(t *testing.T) {
tmpd := createTmpHome(t)
defer os.RemoveAll(tmpd)
err := doRun(t, "-v")
if err != nil {
t.Fatal(err)
}
// make sure things are in path
shellConfig, err := shellConfigFile()
if err != nil {
t.Fatal(err)
}
b, err := ioutil.ReadFile(shellConfig)
if err != nil {
t.Fatal(err)
}
home, err := getHomeDir()
if err != nil {
t.Fatal(err)
}
expected := fmt.Sprintf(`
export PATH=$PATH:%s/.go/bin
export GOPATH=%s/go
export PATH=$PATH:%s/go/bin
`, home, home, home)
if string(b) != expected {
t.Fatalf("%s expected %q, got %q", shellConfig, expected, string(b))
}
}
func TestCommandPathExists(t *testing.T) {
tmpd := createTmpHome(t)
defer os.RemoveAll(tmpd)
// run once
err := doRun(t, "-skip-dl")
if err != nil {
t.Fatal(err)
}
// make sure things are in path
shellConfig, err := shellConfigFile()
if err != nil {
t.Fatal(err)
}
b, err := ioutil.ReadFile(shellConfig)
if err != nil {
t.Fatal(err)
}
home, err := getHomeDir()
if err != nil {
t.Fatal(err)
}
expected := fmt.Sprintf(`
export GOPATH=%s/go
export PATH=$PATH:%s/go/bin
`, home, home)
if string(b) != expected {
t.Fatalf("%s expected %q, got %q", shellConfig, expected, string(b))
}
// run twice
if err := doRun(t, "-skip-dl"); err != nil {
t.Fatal(err)
}
b, err = ioutil.ReadFile(shellConfig)
if err != nil {
t.Fatal(err)
}
if string(b) != expected {
t.Fatalf("%s expected %q, got %q", shellConfig, expected, string(b))
}
}

13
vendor/golang.org/x/tools/cmd/getgo/make.bash generated vendored Normal file
View File

@ -0,0 +1,13 @@
#!/bin/bash
# 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.
set -e -o -x
LDFLAGS="-X main.version=$(git describe --always --dirty='*')"
GOOS=windows GOARCH=386 go build -o build/installer.exe -ldflags="$LDFLAGS"
GOOS=linux GOARCH=386 go build -o build/installer_linux -ldflags="$LDFLAGS"
GOOS=darwin GOARCH=386 go build -o build/installer_darwin -ldflags="$LDFLAGS"

155
vendor/golang.org/x/tools/cmd/getgo/path.go generated vendored Normal file
View File

@ -0,0 +1,155 @@
// 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 !plan9
package main
import (
"bufio"
"context"
"fmt"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
)
const (
bashConfig = ".bash_profile"
zshConfig = ".zshrc"
)
// appendToPATH adds the given path to the PATH environment variable and
// persists it for future sessions.
func appendToPATH(value string) error {
if isInPATH(value) {
return nil
}
return persistEnvVar("PATH", pathVar+envSeparator+value)
}
func isInPATH(dir string) bool {
p := os.Getenv("PATH")
paths := strings.Split(p, envSeparator)
for _, d := range paths {
if d == dir {
return true
}
}
return false
}
func getHomeDir() (string, error) {
home := os.Getenv(homeKey)
if home != "" {
return home, nil
}
u, err := user.Current()
if err != nil {
return "", err
}
return u.HomeDir, nil
}
func checkStringExistsFile(filename, value string) (bool, error) {
file, err := os.OpenFile(filename, os.O_RDONLY, 0600)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if line == value {
return true, nil
}
}
return false, scanner.Err()
}
func appendToFile(filename, value string) error {
verbosef("Adding %q to %s", value, filename)
ok, err := checkStringExistsFile(filename, value)
if err != nil {
return err
}
if ok {
// Nothing to do.
return nil
}
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString(lineEnding + value + lineEnding)
return err
}
func isShell(name string) bool {
return strings.Contains(currentShell(), name)
}
// persistEnvVarWindows sets an environment variable in the Windows
// registry.
func persistEnvVarWindows(name, value string) error {
_, err := runCommand(context.Background(), "powershell", "-command",
fmt.Sprintf(`[Environment]::SetEnvironmentVariable("%s", "%s", "User")`, name, value))
return err
}
func persistEnvVar(name, value string) error {
if runtime.GOOS == "windows" {
if err := persistEnvVarWindows(name, value); err != nil {
return err
}
if isShell("cmd.exe") || isShell("powershell.exe") {
return os.Setenv(strings.ToUpper(name), value)
}
// User is in bash, zsh, etc.
// Also set the environment variable in their shell config.
}
rc, err := shellConfigFile()
if err != nil {
return err
}
line := fmt.Sprintf("export %s=%s", strings.ToUpper(name), value)
if err := appendToFile(rc, line); err != nil {
return err
}
return os.Setenv(strings.ToUpper(name), value)
}
func shellConfigFile() (string, error) {
home, err := getHomeDir()
if err != nil {
return "", err
}
switch {
case isShell("bash"):
return filepath.Join(home, bashConfig), nil
case isShell("zsh"):
return filepath.Join(home, zshConfig), nil
default:
return "", fmt.Errorf("%q is not a supported shell", currentShell())
}
}

58
vendor/golang.org/x/tools/cmd/getgo/path_test.go generated vendored Normal file
View File

@ -0,0 +1,58 @@
// 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 !plan9
package main
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
)
func TestAppendPath(t *testing.T) {
tmpd, err := ioutil.TempDir("", "go")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpd)
if err := os.Setenv("HOME", tmpd); err != nil {
t.Fatal(err)
}
GOPATH := os.Getenv("GOPATH")
if err := appendToPATH(filepath.Join(GOPATH, "bin")); err != nil {
t.Fatal(err)
}
shellConfig, err := shellConfigFile()
if err != nil {
t.Fatal(err)
}
b, err := ioutil.ReadFile(shellConfig)
if err != nil {
t.Fatal(err)
}
expected := "export PATH=" + pathVar + envSeparator + filepath.Join(GOPATH, "bin")
if strings.TrimSpace(string(b)) != expected {
t.Fatalf("expected: %q, got %q", expected, strings.TrimSpace(string(b)))
}
// Check that appendToPATH is idempotent.
if err := appendToPATH(filepath.Join(GOPATH, "bin")); err != nil {
t.Fatal(err)
}
b, err = ioutil.ReadFile(shellConfig)
if err != nil {
t.Fatal(err)
}
if strings.TrimSpace(string(b)) != expected {
t.Fatalf("expected: %q, got %q", expected, strings.TrimSpace(string(b)))
}
}

7
vendor/golang.org/x/tools/cmd/getgo/server/README.md generated vendored Normal file
View File

@ -0,0 +1,7 @@
# getgo server
## Deployment
```
gcloud app deploy --promote --project golang-org
```

7
vendor/golang.org/x/tools/cmd/getgo/server/app.yaml generated vendored Normal file
View File

@ -0,0 +1,7 @@
runtime: go
service: get
api_version: go1
handlers:
- url: /.*
script: _go_app

61
vendor/golang.org/x/tools/cmd/getgo/server/main.go generated vendored Normal file
View File

@ -0,0 +1,61 @@
// 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.
// Command server serves get.golang.org, redirecting users to the appropriate
// getgo installer based on the request path.
package server
import (
"fmt"
"net/http"
"strings"
"time"
)
const (
base = "https://dl.google.com/go/getgo/"
windowsInstaller = base + "installer.exe"
linuxInstaller = base + "installer_linux"
macInstaller = base + "installer_darwin"
)
// substring-based redirects.
var stringMatch = map[string]string{
// via uname, from bash
"MINGW": windowsInstaller, // Reported as MINGW64_NT-10.0 in git bash
"Linux": linuxInstaller,
"Darwin": macInstaller,
}
func init() {
http.HandleFunc("/", handler)
}
func handler(w http.ResponseWriter, r *http.Request) {
if containsIgnoreCase(r.URL.Path, "installer.exe") {
// cache bust
http.Redirect(w, r, windowsInstaller+cacheBust(), http.StatusFound)
return
}
for match, redirect := range stringMatch {
if containsIgnoreCase(r.URL.Path, match) {
http.Redirect(w, r, redirect, http.StatusFound)
return
}
}
http.NotFound(w, r)
}
func containsIgnoreCase(s, substr string) bool {
return strings.Contains(
strings.ToLower(s),
strings.ToLower(substr),
)
}
func cacheBust() string {
return fmt.Sprintf("?%d", time.Now().Nanosecond())
}

133
vendor/golang.org/x/tools/cmd/getgo/steps.go generated vendored Normal file
View File

@ -0,0 +1,133 @@
// 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 !plan9
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
)
type step func(context.Context) error
func welcome(ctx context.Context) error {
fmt.Println("Welcome to the Go installer!")
answer, err := prompt(ctx, "Would you like to install Go? Y/n", "Y")
if err != nil {
return err
}
if strings.ToLower(answer) != "y" {
fmt.Println("Exiting install.")
return exitCleanly
}
return nil
}
func checkOthers(ctx context.Context) error {
// TODO: if go is currently installed install new version over that
path, err := whichGo(ctx)
if err != nil {
fmt.Printf("Cannot check if Go is already installed:\n%v\n", err)
}
if path == "" {
return nil
}
if path != installPath {
fmt.Printf("Go is already installed at %v; remove it from your PATH.\n", path)
}
return nil
}
func chooseVersion(ctx context.Context) error {
if *goVersion != "" {
return nil
}
var err error
*goVersion, err = getLatestGoVersion()
if err != nil {
return err
}
answer, err := prompt(ctx, fmt.Sprintf("The latest Go version is %s, install that? Y/n", *goVersion), "Y")
if err != nil {
return err
}
if strings.ToLower(answer) != "y" {
// TODO: handle passing a version
fmt.Println("Aborting install.")
return exitCleanly
}
return nil
}
func downloadGo(ctx context.Context) error {
answer, err := prompt(ctx, fmt.Sprintf("Download Go version %s to %s? Y/n", *goVersion, installPath), "Y")
if err != nil {
return err
}
if strings.ToLower(answer) != "y" {
fmt.Println("Aborting install.")
return exitCleanly
}
fmt.Printf("Downloading Go version %s to %s\n", *goVersion, installPath)
fmt.Println("This may take a bit of time...")
if err := downloadGoVersion(*goVersion, runtime.GOOS, arch, installPath); err != nil {
return err
}
if err := appendToPATH(filepath.Join(installPath, "bin")); err != nil {
return err
}
fmt.Println("Downloaded!")
return nil
}
func setupGOPATH(ctx context.Context) error {
answer, err := prompt(ctx, "Would you like us to setup your GOPATH? Y/n", "Y")
if err != nil {
return err
}
if strings.ToLower(answer) != "y" {
fmt.Println("Exiting and not setting up GOPATH.")
return exitCleanly
}
fmt.Println("Setting up GOPATH")
home, err := getHomeDir()
if err != nil {
return err
}
gopath := os.Getenv("GOPATH")
if gopath == "" {
// set $GOPATH
gopath = filepath.Join(home, "go")
if err := persistEnvVar("GOPATH", gopath); err != nil {
return err
}
fmt.Println("GOPATH has been set up!")
} else {
verbosef("GOPATH is already set to %s", gopath)
}
if err := appendToPATH(filepath.Join(gopath, "bin")); err != nil {
return err
}
return persistEnvChangesForSession()
}

38
vendor/golang.org/x/tools/cmd/getgo/system.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
// 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 !plan9
package main
import (
"bytes"
"context"
"os/exec"
"runtime"
"strings"
)
// arch contains either amd64 or 386.
var arch = func() string {
cmd := exec.Command("uname", "-m") // "x86_64"
if runtime.GOOS == "windows" {
cmd = exec.Command("powershell", "-command", "(Get-WmiObject -Class Win32_ComputerSystem).SystemType") // "x64-based PC"
}
out, err := cmd.Output()
if err != nil {
// a sensible default?
return "amd64"
}
if bytes.Contains(out, []byte("64")) {
return "amd64"
}
return "386"
}()
func findGo(ctx context.Context, cmd string) (string, error) {
out, err := exec.CommandContext(ctx, cmd, "go").CombinedOutput()
return strings.TrimSpace(string(out)), err
}

55
vendor/golang.org/x/tools/cmd/getgo/system_unix.go generated vendored Normal file
View File

@ -0,0 +1,55 @@
// 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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package main
import (
"context"
"fmt"
"os"
"path/filepath"
)
const (
envSeparator = ":"
homeKey = "HOME"
lineEnding = "\n"
pathVar = "$PATH"
)
var installPath = func() string {
home, err := getHomeDir()
if err != nil {
return "/usr/local/go"
}
return filepath.Join(home, ".go")
}()
func whichGo(ctx context.Context) (string, error) {
return findGo(ctx, "which")
}
func isWindowsXP() bool {
return false
}
func currentShell() string {
return os.Getenv("SHELL")
}
func persistEnvChangesForSession() error {
shellConfig, err := shellConfigFile()
if err != nil {
return err
}
fmt.Println()
fmt.Printf("One more thing! Run `source %s` to persist the\n", shellConfig)
fmt.Println("new environment variables to your current session, or open a")
fmt.Println("new shell prompt.")
return nil
}

86
vendor/golang.org/x/tools/cmd/getgo/system_windows.go generated vendored Normal file
View File

@ -0,0 +1,86 @@
// 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 windows
package main
import (
"context"
"log"
"os"
"syscall"
"unsafe"
)
const (
envSeparator = ";"
homeKey = "USERPROFILE"
lineEnding = "/r/n"
pathVar = "$env:Path"
)
var installPath = `c:\go`
func isWindowsXP() bool {
v, err := syscall.GetVersion()
if err != nil {
log.Fatalf("GetVersion failed: %v", err)
}
major := byte(v)
return major < 6
}
func whichGo(ctx context.Context) (string, error) {
return findGo(ctx, "where")
}
// currentShell reports the current shell.
// It might be "powershell.exe", "cmd.exe" or any of the *nix shells.
//
// Returns empty string if the shell is unknown.
func currentShell() string {
shell := os.Getenv("SHELL")
if shell != "" {
return shell
}
pid := os.Getppid()
pe, err := getProcessEntry(pid)
if err != nil {
verbosef("getting shell from process entry failed: %v", err)
return ""
}
return syscall.UTF16ToString(pe.ExeFile[:])
}
func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) {
// From https://go.googlesource.com/go/+/go1.8.3/src/syscall/syscall_windows.go#941
snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
if err != nil {
return nil, err
}
defer syscall.CloseHandle(snapshot)
var procEntry syscall.ProcessEntry32
procEntry.Size = uint32(unsafe.Sizeof(procEntry))
if err = syscall.Process32First(snapshot, &procEntry); err != nil {
return nil, err
}
for {
if procEntry.ProcessID == uint32(pid) {
return &procEntry, nil
}
if err := syscall.Process32Next(snapshot, &procEntry); err != nil {
return nil, err
}
}
}
func persistEnvChangesForSession() error {
return nil
}

19
vendor/golang.org/x/tools/cmd/getgo/upload.bash generated vendored Normal file
View File

@ -0,0 +1,19 @@
#!/bin/bash
# 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.
if ! command -v gsutil 2>&1 > /dev/null; then
echo "Install gsutil:"
echo
echo " https://cloud.google.com/storage/docs/gsutil_install#sdk-install"
fi
if [ ! -d build ]; then
echo "Run make.bash first"
fi
set -e -o -x
gsutil -m cp -a public-read build/* gs://golang/getgo

View File

@ -0,0 +1,289 @@
// 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.
// The go-contrib-init command helps new Go contributors get their development
// environment set up for the Go contribution process.
//
// It aims to be a complement or alternative to https://golang.org/doc/contribute.html.
package main
import (
"bytes"
"flag"
"fmt"
"go/build"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strings"
)
var (
repo = flag.String("repo", detectrepo(), "Which go repo you want to contribute to. Use \"go\" for the core, or e.g. \"net\" for golang.org/x/net/*")
dry = flag.Bool("dry-run", false, "Fail with problems instead of trying to fix things.")
)
func main() {
log.SetFlags(0)
flag.Parse()
checkCLA()
checkGoroot()
checkWorkingDir()
checkGitOrigin()
checkGitCodeReview()
fmt.Print("All good. Happy hacking!\n" +
"Remember to squash your revised commits and preserve the magic Change-Id lines.\n" +
"Next steps: https://golang.org/doc/contribute.html#commit_changes\n")
}
func detectrepo() string {
wd, err := os.Getwd()
if err != nil {
return "go"
}
for _, path := range filepath.SplitList(build.Default.GOPATH) {
rightdir := filepath.Join(path, "src", "golang.org", "x") + string(os.PathSeparator)
if strings.HasPrefix(wd, rightdir) {
tail := wd[len(rightdir):]
end := strings.Index(tail, string(os.PathSeparator))
if end > 0 {
repo := tail[:end]
return repo
}
}
}
return "go"
}
var googleSourceRx = regexp.MustCompile(`(?m)^(go|go-review)?\.googlesource.com\b`)
func checkCLA() {
slurp, err := ioutil.ReadFile(cookiesFile())
if err != nil && !os.IsNotExist(err) {
log.Fatal(err)
}
if googleSourceRx.Match(slurp) {
// Probably good.
return
}
log.Fatal("Your .gitcookies file isn't configured.\n" +
"Next steps:\n" +
" * Submit a CLA (https://golang.org/doc/contribute.html#cla) if not done\n" +
" * Go to https://go.googlesource.com/ and click \"Generate Password\" at the top,\n" +
" then follow instructions.\n" +
" * Run go-contrib-init again.\n")
}
func expandUser(s string) string {
env := "HOME"
if runtime.GOOS == "windows" {
env = "USERPROFILE"
} else if runtime.GOOS == "plan9" {
env = "home"
}
home := os.Getenv(env)
if home == "" {
return s
}
if len(s) >= 2 && s[0] == '~' && os.IsPathSeparator(s[1]) {
if runtime.GOOS == "windows" {
s = filepath.ToSlash(filepath.Join(home, s[2:]))
} else {
s = filepath.Join(home, s[2:])
}
}
return os.Expand(s, func(env string) string {
if env == "HOME" {
return home
}
return os.Getenv(env)
})
}
func cookiesFile() string {
out, _ := exec.Command("git", "config", "http.cookiefile").Output()
if s := strings.TrimSpace(string(out)); s != "" {
if strings.HasPrefix(s, "~") {
s = expandUser(s)
}
return s
}
if runtime.GOOS == "windows" {
return filepath.Join(os.Getenv("USERPROFILE"), ".gitcookies")
}
return filepath.Join(os.Getenv("HOME"), ".gitcookies")
}
func checkGoroot() {
v := os.Getenv("GOROOT")
if v == "" {
return
}
if *repo == "go" {
if strings.HasPrefix(v, "/usr/") {
log.Fatalf("Your GOROOT environment variable is set to %q\n"+
"This is almost certainly not what you want. Either unset\n"+
"your GOROOT or set it to the path of your development version\n"+
"of Go.", v)
}
slurp, err := ioutil.ReadFile(filepath.Join(v, "VERSION"))
if err == nil {
slurp = bytes.TrimSpace(slurp)
log.Fatalf("Your GOROOT environment variable is set to %q\n"+
"But that path is to a binary release of Go, with VERSION file %q.\n"+
"You should hack on Go in a fresh checkout of Go. Fix or unset your GOROOT.\n",
v, slurp)
}
}
}
func checkWorkingDir() {
wd, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
if *repo == "go" {
if inGoPath(wd) {
log.Fatalf(`You can't work on Go from within your GOPATH. Please checkout Go outside of your GOPATH
Current directory: %s
GOPATH: %s
`, wd, os.Getenv("GOPATH"))
}
return
}
gopath := firstGoPath()
if gopath == "" {
log.Fatal("Your GOPATH is not set, please set it")
}
rightdir := filepath.Join(gopath, "src", "golang.org", "x", *repo)
if !strings.HasPrefix(wd, rightdir) {
dirExists, err := exists(rightdir)
if err != nil {
log.Fatal(err)
}
if !dirExists {
log.Fatalf("The repo you want to work on is currently not on your system.\n"+
"Run %q to obtain this repo\n"+
"then go to the directory %q\n",
"go get -d golang.org/x/"+*repo, rightdir)
}
log.Fatalf("Your current directory is:%q\n"+
"Working on golang/x/%v requires you be in %q\n",
wd, *repo, rightdir)
}
}
func firstGoPath() string {
list := filepath.SplitList(build.Default.GOPATH)
if len(list) < 1 {
return ""
}
return list[0]
}
func exists(path string) (bool, error) {
_, err := os.Stat(path)
if os.IsNotExist(err) {
return false, nil
}
return true, err
}
func inGoPath(wd string) bool {
if os.Getenv("GOPATH") == "" {
return false
}
for _, path := range filepath.SplitList(os.Getenv("GOPATH")) {
if strings.HasPrefix(wd, filepath.Join(path, "src")) {
return true
}
}
return false
}
// mostly check that they didn't clone from github
func checkGitOrigin() {
if _, err := exec.LookPath("git"); err != nil {
log.Fatalf("You don't appear to have git installed. Do that.")
}
wantRemote := "https://go.googlesource.com/" + *repo
remotes, err := exec.Command("git", "remote", "-v").Output()
if err != nil {
msg := cmdErr(err)
if strings.Contains(msg, "Not a git repository") {
log.Fatalf("Your current directory is not in a git checkout of %s", wantRemote)
}
log.Fatalf("Error running git remote -v: %v", msg)
}
matches := 0
for _, line := range strings.Split(string(remotes), "\n") {
line = strings.TrimSpace(line)
if !strings.HasPrefix(line, "origin") {
continue
}
if !strings.Contains(line, wantRemote) {
curRemote := strings.Fields(strings.TrimPrefix(line, "origin"))[0]
// TODO: if not in dryRun mode, just fix it?
log.Fatalf("Current directory's git was cloned from %q; origin should be %q", curRemote, wantRemote)
}
matches++
}
if matches == 0 {
log.Fatalf("git remote -v output didn't contain expected %q. Got:\n%s", wantRemote, remotes)
}
}
func cmdErr(err error) string {
if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
return fmt.Sprintf("%s: %s", err, ee.Stderr)
}
return fmt.Sprint(err)
}
func checkGitCodeReview() {
if _, err := exec.LookPath("git-codereview"); err != nil {
if *dry {
log.Fatalf("You don't appear to have git-codereview tool. While this is technically optional,\n" +
"almost all Go contributors use it. Our documentation and this tool assume it is used.\n" +
"To install it, run:\n\n\t$ go get golang.org/x/review/git-codereview\n\n(Then run go-contrib-init again)")
}
err := exec.Command("go", "get", "golang.org/x/review/git-codereview").Run()
if err != nil {
log.Fatalf("Error running go get golang.org/x/review/git-codereview: %v", cmdErr(err))
}
log.Printf("Installed git-codereview (ran `go get golang.org/x/review/git-codereview`)")
}
missing := false
for _, cmd := range []string{"change", "gofmt", "mail", "pending", "submit", "sync"} {
v, _ := exec.Command("git", "config", "alias."+cmd).Output()
if strings.Contains(string(v), "codereview") {
continue
}
if *dry {
log.Printf("Missing alias. Run:\n\t$ git config alias.%s \"codereview %s\"", cmd, cmd)
missing = true
} else {
err := exec.Command("git", "config", "alias."+cmd, "codereview "+cmd).Run()
if err != nil {
log.Fatalf("Error setting alias.%s: %v", cmd, cmdErr(err))
}
}
}
if missing {
log.Fatalf("Missing aliases. (While optional, this tool assumes you use them.)")
}
}

View File

@ -0,0 +1,35 @@
package main
import (
"os"
"runtime"
"testing"
)
func TestExpandUser(t *testing.T) {
env := "HOME"
if runtime.GOOS == "windows" {
env = "USERPROFILE"
} else if runtime.GOOS == "plan9" {
env = "home"
}
oldenv := os.Getenv(env)
os.Setenv(env, "/home/gopher")
defer os.Setenv(env, oldenv)
tests := []struct {
input string
want string
}{
{input: "~/foo", want: "/home/gopher/foo"},
{input: "${HOME}/foo", want: "/home/gopher/foo"},
{input: "/~/foo", want: "/~/foo"},
}
for _, tt := range tests {
got := expandUser(tt.input)
if got != tt.want {
t.Fatalf("want %q, but %q", tt.want, got)
}
}
}

69
vendor/golang.org/x/tools/cmd/godex/doc.go generated vendored Normal file
View File

@ -0,0 +1,69 @@
// 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.
// The godex command prints (dumps) exported information of packages
// or selected package objects.
//
// In contrast to godoc, godex extracts this information from compiled
// object files. Hence the exported data is truly what a compiler will
// see, at the cost of missing commentary.
//
// Usage: godex [flags] {path[.name]}
//
// Each argument must be a (possibly partial) package path, optionally
// followed by a dot and the name of a package object:
//
// godex math
// godex math.Sin
// godex math.Sin fmt.Printf
// godex go/types
//
// godex automatically tries all possible package path prefixes if only a
// partial package path is given. For instance, for the path "go/types",
// godex prepends "golang.org/x/tools".
//
// The prefixes are computed by searching the directories specified by
// the GOROOT and GOPATH environment variables (and by excluding the
// build OS- and architecture-specific directory names from the path).
// The search order is depth-first and alphabetic; for a partial path
// "foo", a package "a/foo" is found before "b/foo".
//
// Absolute and relative paths may be provided, which disable automatic
// prefix generation:
//
// godex $GOROOT/pkg/darwin_amd64/sort
// godex ./sort
//
// All but the last path element may contain dots; a dot in the last path
// element separates the package path from the package object name. If the
// last path element contains a dot, terminate the argument with another
// dot (indicating an empty object name). For instance, the path for a
// package foo.bar would be specified as in:
//
// godex foo.bar.
//
// The flags are:
//
// -s=""
// only consider packages from src, where src is one of the supported compilers
// -v=false
// verbose mode
//
// The following sources (-s arguments) are supported:
//
// gc
// gc-generated object files
// gccgo
// gccgo-generated object files
// gccgo-new
// gccgo-generated object files using a condensed format (experimental)
// source
// (uncompiled) source code (not yet implemented)
//
// If no -s argument is provided, godex will try to find a matching source.
//
package main // import "golang.org/x/tools/cmd/godex"
// BUG(gri): support for -s=source is not yet implemented
// BUG(gri): gccgo-importing appears to have occasional problems stalling godex; try -s=gc as work-around

13
vendor/golang.org/x/tools/cmd/godex/gc.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// 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.
// This file implements access to gc-generated export data.
package main
import "go/importer"
func init() {
register("gc", importer.For("gc", nil))
}

34
vendor/golang.org/x/tools/cmd/godex/gccgo.go generated vendored Normal file
View File

@ -0,0 +1,34 @@
// 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.
// This file implements access to gccgo-generated export data.
package main
import (
"go/importer"
"go/types"
)
func init() {
register("gccgo", importer.For("gccgo", nil))
}
// Print the extra gccgo compiler data for this package, if it exists.
func (p *printer) printGccgoExtra(pkg *types.Package) {
// Disabled for now.
// TODO(gri) address this at some point.
// if initdata, ok := initmap[pkg]; ok {
// p.printf("/*\npriority %d\n", initdata.Priority)
// p.printDecl("init", len(initdata.Inits), func() {
// for _, init := range initdata.Inits {
// p.printf("%s %s %d\n", init.Name, init.InitFunc, init.Priority)
// }
// })
// p.print("*/\n")
// }
}

211
vendor/golang.org/x/tools/cmd/godex/godex.go generated vendored Normal file
View File

@ -0,0 +1,211 @@
// 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.
package main
import (
"errors"
"flag"
"fmt"
"go/build"
"go/types"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
var (
source = flag.String("s", "", "only consider packages from src, where src is one of the supported compilers")
verbose = flag.Bool("v", false, "verbose mode")
)
// lists of registered sources and corresponding importers
var (
sources []string
importers []types.Importer
importFailed = errors.New("import failed")
)
func usage() {
fmt.Fprintln(os.Stderr, "usage: godex [flags] {path|qualifiedIdent}")
flag.PrintDefaults()
os.Exit(2)
}
func report(msg string) {
fmt.Fprintln(os.Stderr, "error: "+msg)
os.Exit(2)
}
func main() {
flag.Usage = usage
flag.Parse()
if flag.NArg() == 0 {
report("no package name, path, or file provided")
}
var imp types.Importer = new(tryImporters)
if *source != "" {
imp = lookup(*source)
if imp == nil {
report("source (-s argument) must be one of: " + strings.Join(sources, ", "))
}
}
for _, arg := range flag.Args() {
path, name := splitPathIdent(arg)
logf("\tprocessing %q: path = %q, name = %s\n", arg, path, name)
// generate possible package path prefixes
// (at the moment we do this for each argument - should probably cache the generated prefixes)
prefixes := make(chan string)
go genPrefixes(prefixes, !filepath.IsAbs(path) && !build.IsLocalImport(path))
// import package
pkg, err := tryPrefixes(prefixes, path, imp)
if err != nil {
logf("\t=> ignoring %q: %s\n", path, err)
continue
}
// filter objects if needed
var filter func(types.Object) bool
if name != "" {
filter = func(obj types.Object) bool {
// TODO(gri) perhaps use regular expression matching here?
return obj.Name() == name
}
}
// print contents
print(os.Stdout, pkg, filter)
}
}
func logf(format string, args ...interface{}) {
if *verbose {
fmt.Fprintf(os.Stderr, format, args...)
}
}
// splitPathIdent splits a path.name argument into its components.
// All but the last path element may contain dots.
func splitPathIdent(arg string) (path, name string) {
if i := strings.LastIndex(arg, "."); i >= 0 {
if j := strings.LastIndex(arg, "/"); j < i {
// '.' is not part of path
path = arg[:i]
name = arg[i+1:]
return
}
}
path = arg
return
}
// tryPrefixes tries to import the package given by (the possibly partial) path using the given importer imp
// by prepending all possible prefixes to path. It returns with the first package that it could import, or
// with an error.
func tryPrefixes(prefixes chan string, path string, imp types.Importer) (pkg *types.Package, err error) {
for prefix := range prefixes {
actual := path
if prefix == "" {
// don't use filepath.Join as it will sanitize the path and remove
// a leading dot and then the path is not recognized as a relative
// package path by the importers anymore
logf("\ttrying no prefix\n")
} else {
actual = filepath.Join(prefix, path)
logf("\ttrying prefix %q\n", prefix)
}
pkg, err = imp.Import(actual)
if err == nil {
break
}
logf("\t=> importing %q failed: %s\n", actual, err)
}
return
}
// tryImporters is an importer that tries all registered importers
// successively until one of them succeeds or all of them failed.
type tryImporters struct{}
func (t *tryImporters) Import(path string) (pkg *types.Package, err error) {
for i, imp := range importers {
logf("\t\ttrying %s import\n", sources[i])
pkg, err = imp.Import(path)
if err == nil {
break
}
logf("\t\t=> %s import failed: %s\n", sources[i], err)
}
return
}
type protector struct {
imp types.Importer
}
func (p *protector) Import(path string) (pkg *types.Package, err error) {
defer func() {
if recover() != nil {
pkg = nil
err = importFailed
}
}()
return p.imp.Import(path)
}
// protect protects an importer imp from panics and returns the protected importer.
func protect(imp types.Importer) types.Importer {
return &protector{imp}
}
// register registers an importer imp for a given source src.
func register(src string, imp types.Importer) {
if lookup(src) != nil {
panic(src + " importer already registered")
}
sources = append(sources, src)
importers = append(importers, protect(imp))
}
// lookup returns the importer imp for a given source src.
func lookup(src string) types.Importer {
for i, s := range sources {
if s == src {
return importers[i]
}
}
return nil
}
func genPrefixes(out chan string, all bool) {
out <- ""
if all {
platform := build.Default.GOOS + "_" + build.Default.GOARCH
dirnames := append([]string{build.Default.GOROOT}, filepath.SplitList(build.Default.GOPATH)...)
for _, dirname := range dirnames {
walkDir(filepath.Join(dirname, "pkg", platform), "", out)
}
}
close(out)
}
func walkDir(dirname, prefix string, out chan string) {
fiList, err := ioutil.ReadDir(dirname)
if err != nil {
return
}
for _, fi := range fiList {
if fi.IsDir() && !strings.HasPrefix(fi.Name(), ".") {
prefix := filepath.Join(prefix, fi.Name())
out <- prefix
walkDir(filepath.Join(dirname, fi.Name()), prefix, out)
}
}
}

13
vendor/golang.org/x/tools/cmd/godex/isAlias18.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// 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
import "go/types"
func isAlias(obj *types.TypeName) bool {
return false // there are no type aliases before Go 1.9
}

13
vendor/golang.org/x/tools/cmd/godex/isAlias19.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// 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
import "go/types"
func isAlias(obj *types.TypeName) bool {
return obj.IsAlias()
}

373
vendor/golang.org/x/tools/cmd/godex/print.go generated vendored Normal file
View File

@ -0,0 +1,373 @@
// 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.
package main
import (
"bytes"
"fmt"
exact "go/constant"
"go/token"
"go/types"
"io"
"math/big"
)
// TODO(gri) use tabwriter for alignment?
func print(w io.Writer, pkg *types.Package, filter func(types.Object) bool) {
var p printer
p.pkg = pkg
p.printPackage(pkg, filter)
p.printGccgoExtra(pkg)
io.Copy(w, &p.buf)
}
type printer struct {
pkg *types.Package
buf bytes.Buffer
indent int // current indentation level
last byte // last byte written
}
func (p *printer) print(s string) {
// Write the string one byte at a time. We care about the presence of
// newlines for indentation which we will see even in the presence of
// (non-corrupted) Unicode; no need to read one rune at a time.
for i := 0; i < len(s); i++ {
ch := s[i]
if ch != '\n' && p.last == '\n' {
// Note: This could lead to a range overflow for very large
// indentations, but it's extremely unlikely to happen for
// non-pathological code.
p.buf.WriteString("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"[:p.indent])
}
p.buf.WriteByte(ch)
p.last = ch
}
}
func (p *printer) printf(format string, args ...interface{}) {
p.print(fmt.Sprintf(format, args...))
}
// methodsFor returns the named type and corresponding methods if the type
// denoted by obj is not an interface and has methods. Otherwise it returns
// the zero value.
func methodsFor(obj *types.TypeName) (*types.Named, []*types.Selection) {
named, _ := obj.Type().(*types.Named)
if named == nil {
// A type name's type can also be the
// exported basic type unsafe.Pointer.
return nil, nil
}
if _, ok := named.Underlying().(*types.Interface); ok {
// ignore interfaces
return nil, nil
}
methods := combinedMethodSet(named)
if len(methods) == 0 {
return nil, nil
}
return named, methods
}
func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) {
// collect objects by kind
var (
consts []*types.Const
typem []*types.Named // non-interface types with methods
typez []*types.TypeName // interfaces or types without methods
vars []*types.Var
funcs []*types.Func
builtins []*types.Builtin
methods = make(map[*types.Named][]*types.Selection) // method sets for named types
)
scope := pkg.Scope()
for _, name := range scope.Names() {
obj := scope.Lookup(name)
if obj.Exported() {
// collect top-level exported and possibly filtered objects
if filter == nil || filter(obj) {
switch obj := obj.(type) {
case *types.Const:
consts = append(consts, obj)
case *types.TypeName:
// group into types with methods and types without
if named, m := methodsFor(obj); named != nil {
typem = append(typem, named)
methods[named] = m
} else {
typez = append(typez, obj)
}
case *types.Var:
vars = append(vars, obj)
case *types.Func:
funcs = append(funcs, obj)
case *types.Builtin:
// for unsafe.Sizeof, etc.
builtins = append(builtins, obj)
}
}
} else if filter == nil {
// no filtering: collect top-level unexported types with methods
if obj, _ := obj.(*types.TypeName); obj != nil {
// see case *types.TypeName above
if named, m := methodsFor(obj); named != nil {
typem = append(typem, named)
methods[named] = m
}
}
}
}
p.printf("package %s // %q\n", pkg.Name(), pkg.Path())
p.printDecl("const", len(consts), func() {
for _, obj := range consts {
p.printObj(obj)
p.print("\n")
}
})
p.printDecl("var", len(vars), func() {
for _, obj := range vars {
p.printObj(obj)
p.print("\n")
}
})
p.printDecl("type", len(typez), func() {
for _, obj := range typez {
p.printf("%s ", obj.Name())
typ := obj.Type()
if isAlias(obj) {
p.print("= ")
p.writeType(p.pkg, typ)
} else {
p.writeType(p.pkg, typ.Underlying())
}
p.print("\n")
}
})
// non-interface types with methods
for _, named := range typem {
first := true
if obj := named.Obj(); obj.Exported() {
if first {
p.print("\n")
first = false
}
p.printf("type %s ", obj.Name())
p.writeType(p.pkg, named.Underlying())
p.print("\n")
}
for _, m := range methods[named] {
if obj := m.Obj(); obj.Exported() {
if first {
p.print("\n")
first = false
}
p.printFunc(m.Recv(), obj.(*types.Func))
p.print("\n")
}
}
}
if len(funcs) > 0 {
p.print("\n")
for _, obj := range funcs {
p.printFunc(nil, obj)
p.print("\n")
}
}
// TODO(gri) better handling of builtins (package unsafe only)
if len(builtins) > 0 {
p.print("\n")
for _, obj := range builtins {
p.printf("func %s() // builtin\n", obj.Name())
}
}
p.print("\n")
}
func (p *printer) printDecl(keyword string, n int, printGroup func()) {
switch n {
case 0:
// nothing to do
case 1:
p.printf("\n%s ", keyword)
printGroup()
default:
p.printf("\n%s (\n", keyword)
p.indent++
printGroup()
p.indent--
p.print(")\n")
}
}
// absInt returns the absolute value of v as a *big.Int.
// v must be a numeric value.
func absInt(v exact.Value) *big.Int {
// compute big-endian representation of v
b := exact.Bytes(v) // little-endian
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
b[i], b[j] = b[j], b[i]
}
return new(big.Int).SetBytes(b)
}
var (
one = big.NewRat(1, 1)
ten = big.NewRat(10, 1)
)
// floatString returns the string representation for a
// numeric value v in normalized floating-point format.
func floatString(v exact.Value) string {
if exact.Sign(v) == 0 {
return "0.0"
}
// x != 0
// convert |v| into a big.Rat x
x := new(big.Rat).SetFrac(absInt(exact.Num(v)), absInt(exact.Denom(v)))
// normalize x and determine exponent e
// (This is not very efficient, but also not speed-critical.)
var e int
for x.Cmp(ten) >= 0 {
x.Quo(x, ten)
e++
}
for x.Cmp(one) < 0 {
x.Mul(x, ten)
e--
}
// TODO(gri) Values such as 1/2 are easier to read in form 0.5
// rather than 5.0e-1. Similarly, 1.0e1 is easier to read as
// 10.0. Fine-tune best exponent range for readability.
s := x.FloatString(100) // good-enough precision
// trim trailing 0's
i := len(s)
for i > 0 && s[i-1] == '0' {
i--
}
s = s[:i]
// add a 0 if the number ends in decimal point
if len(s) > 0 && s[len(s)-1] == '.' {
s += "0"
}
// add exponent and sign
if e != 0 {
s += fmt.Sprintf("e%+d", e)
}
if exact.Sign(v) < 0 {
s = "-" + s
}
// TODO(gri) If v is a "small" fraction (i.e., numerator and denominator
// are just a small number of decimal digits), add the exact fraction as
// a comment. For instance: 3.3333...e-1 /* = 1/3 */
return s
}
// valString returns the string representation for the value v.
// Setting floatFmt forces an integer value to be formatted in
// normalized floating-point format.
// TODO(gri) Move this code into package exact.
func valString(v exact.Value, floatFmt bool) string {
switch v.Kind() {
case exact.Int:
if floatFmt {
return floatString(v)
}
case exact.Float:
return floatString(v)
case exact.Complex:
re := exact.Real(v)
im := exact.Imag(v)
var s string
if exact.Sign(re) != 0 {
s = floatString(re)
if exact.Sign(im) >= 0 {
s += " + "
} else {
s += " - "
im = exact.UnaryOp(token.SUB, im, 0) // negate im
}
}
// im != 0, otherwise v would be exact.Int or exact.Float
return s + floatString(im) + "i"
}
return v.String()
}
func (p *printer) printObj(obj types.Object) {
p.print(obj.Name())
typ, basic := obj.Type().Underlying().(*types.Basic)
if basic && typ.Info()&types.IsUntyped != 0 {
// don't write untyped types
} else {
p.print(" ")
p.writeType(p.pkg, obj.Type())
}
if obj, ok := obj.(*types.Const); ok {
floatFmt := basic && typ.Info()&(types.IsFloat|types.IsComplex) != 0
p.print(" = ")
p.print(valString(obj.Val(), floatFmt))
}
}
func (p *printer) printFunc(recvType types.Type, obj *types.Func) {
p.print("func ")
sig := obj.Type().(*types.Signature)
if recvType != nil {
p.print("(")
p.writeType(p.pkg, recvType)
p.print(") ")
}
p.print(obj.Name())
p.writeSignature(p.pkg, sig)
}
// combinedMethodSet returns the method set for a named type T
// merged with all the methods of *T that have different names than
// the methods of T.
//
// combinedMethodSet is analogous to types/typeutil.IntuitiveMethodSet
// but doesn't require a MethodSetCache.
// TODO(gri) If this functionality doesn't change over time, consider
// just calling IntuitiveMethodSet eventually.
func combinedMethodSet(T *types.Named) []*types.Selection {
// method set for T
mset := types.NewMethodSet(T)
var res []*types.Selection
for i, n := 0, mset.Len(); i < n; i++ {
res = append(res, mset.At(i))
}
// add all *T methods with names different from T methods
pmset := types.NewMethodSet(types.NewPointer(T))
for i, n := 0, pmset.Len(); i < n; i++ {
pm := pmset.At(i)
if obj := pm.Obj(); mset.Lookup(obj.Pkg(), obj.Name()) == nil {
res = append(res, pm)
}
}
return res
}

19
vendor/golang.org/x/tools/cmd/godex/source.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
// 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.
// This file implements access to export data from source.
package main
import "go/types"
func init() {
register("source", sourceImporter{})
}
type sourceImporter struct{}
func (sourceImporter) Import(path string) (*types.Package, error) {
panic("unimplemented")
}

242
vendor/golang.org/x/tools/cmd/godex/writetype.go generated vendored Normal file
View File

@ -0,0 +1,242 @@
// 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.
// This file implements writing of types. The functionality is lifted
// directly from go/types, but now contains various modifications for
// nicer output.
//
// TODO(gri) back-port once we have a fixed interface and once the
// go/types API is not frozen anymore for the 1.3 release; and remove
// this implementation if possible.
package main
import "go/types"
func (p *printer) writeType(this *types.Package, typ types.Type) {
p.writeTypeInternal(this, typ, make([]types.Type, 8))
}
// From go/types - leave for now to ease back-porting this code.
const GcCompatibilityMode = false
func (p *printer) writeTypeInternal(this *types.Package, typ types.Type, visited []types.Type) {
// Theoretically, this is a quadratic lookup algorithm, but in
// practice deeply nested composite types with unnamed component
// types are uncommon. This code is likely more efficient than
// using a map.
for _, t := range visited {
if t == typ {
p.printf("○%T", typ) // cycle to typ
return
}
}
visited = append(visited, typ)
switch t := typ.(type) {
case nil:
p.print("<nil>")
case *types.Basic:
if t.Kind() == types.UnsafePointer {
p.print("unsafe.")
}
if GcCompatibilityMode {
// forget the alias names
switch t.Kind() {
case types.Byte:
t = types.Typ[types.Uint8]
case types.Rune:
t = types.Typ[types.Int32]
}
}
p.print(t.Name())
case *types.Array:
p.printf("[%d]", t.Len())
p.writeTypeInternal(this, t.Elem(), visited)
case *types.Slice:
p.print("[]")
p.writeTypeInternal(this, t.Elem(), visited)
case *types.Struct:
n := t.NumFields()
if n == 0 {
p.print("struct{}")
return
}
p.print("struct {\n")
p.indent++
for i := 0; i < n; i++ {
f := t.Field(i)
if !f.Anonymous() {
p.printf("%s ", f.Name())
}
p.writeTypeInternal(this, f.Type(), visited)
if tag := t.Tag(i); tag != "" {
p.printf(" %q", tag)
}
p.print("\n")
}
p.indent--
p.print("}")
case *types.Pointer:
p.print("*")
p.writeTypeInternal(this, t.Elem(), visited)
case *types.Tuple:
p.writeTuple(this, t, false, visited)
case *types.Signature:
p.print("func")
p.writeSignatureInternal(this, t, visited)
case *types.Interface:
// We write the source-level methods and embedded types rather
// than the actual method set since resolved method signatures
// may have non-printable cycles if parameters have anonymous
// interface types that (directly or indirectly) embed the
// current interface. For instance, consider the result type
// of m:
//
// type T interface{
// m() interface{ T }
// }
//
n := t.NumMethods()
if n == 0 {
p.print("interface{}")
return
}
p.print("interface {\n")
p.indent++
if GcCompatibilityMode {
// print flattened interface
// (useful to compare against gc-generated interfaces)
for i := 0; i < n; i++ {
m := t.Method(i)
p.print(m.Name())
p.writeSignatureInternal(this, m.Type().(*types.Signature), visited)
p.print("\n")
}
} else {
// print explicit interface methods and embedded types
for i, n := 0, t.NumExplicitMethods(); i < n; i++ {
m := t.ExplicitMethod(i)
p.print(m.Name())
p.writeSignatureInternal(this, m.Type().(*types.Signature), visited)
p.print("\n")
}
for i, n := 0, t.NumEmbeddeds(); i < n; i++ {
typ := t.Embedded(i)
p.writeTypeInternal(this, typ, visited)
p.print("\n")
}
}
p.indent--
p.print("}")
case *types.Map:
p.print("map[")
p.writeTypeInternal(this, t.Key(), visited)
p.print("]")
p.writeTypeInternal(this, t.Elem(), visited)
case *types.Chan:
var s string
var parens bool
switch t.Dir() {
case types.SendRecv:
s = "chan "
// chan (<-chan T) requires parentheses
if c, _ := t.Elem().(*types.Chan); c != nil && c.Dir() == types.RecvOnly {
parens = true
}
case types.SendOnly:
s = "chan<- "
case types.RecvOnly:
s = "<-chan "
default:
panic("unreachable")
}
p.print(s)
if parens {
p.print("(")
}
p.writeTypeInternal(this, t.Elem(), visited)
if parens {
p.print(")")
}
case *types.Named:
s := "<Named w/o object>"
if obj := t.Obj(); obj != nil {
if pkg := obj.Pkg(); pkg != nil {
if pkg != this {
p.print(pkg.Path())
p.print(".")
}
// TODO(gri): function-local named types should be displayed
// differently from named types at package level to avoid
// ambiguity.
}
s = obj.Name()
}
p.print(s)
default:
// For externally defined implementations of Type.
p.print(t.String())
}
}
func (p *printer) writeTuple(this *types.Package, tup *types.Tuple, variadic bool, visited []types.Type) {
p.print("(")
for i, n := 0, tup.Len(); i < n; i++ {
if i > 0 {
p.print(", ")
}
v := tup.At(i)
if name := v.Name(); name != "" {
p.print(name)
p.print(" ")
}
typ := v.Type()
if variadic && i == n-1 {
p.print("...")
typ = typ.(*types.Slice).Elem()
}
p.writeTypeInternal(this, typ, visited)
}
p.print(")")
}
func (p *printer) writeSignature(this *types.Package, sig *types.Signature) {
p.writeSignatureInternal(this, sig, make([]types.Type, 8))
}
func (p *printer) writeSignatureInternal(this *types.Package, sig *types.Signature, visited []types.Type) {
p.writeTuple(this, sig.Params(), sig.Variadic(), visited)
res := sig.Results()
n := res.Len()
if n == 0 {
// no result
return
}
p.print(" ")
if n == 1 && res.At(0).Name() == "" {
// single unnamed result
p.writeTypeInternal(this, res.At(0).Type(), visited)
return
}
// multiple or named result(s)
p.writeTuple(this, res, false, visited)
}

56
vendor/golang.org/x/tools/cmd/godoc/README.godoc-app generated vendored Normal file
View 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
View 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")
}

77
vendor/golang.org/x/tools/cmd/godoc/autocert.go generated vendored Normal file
View File

@ -0,0 +1,77 @@
// 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() {
serveAutoCertHook = serveAutoCert
}
func serveAutoCert(h http.Handler) error {
m := autocert.Manager{
Cache: autocert.DirCache(*autoCertDirFlag),
Prompt: autocert.AcceptTOS,
}
if *autoCertHostFlag != "" {
m.HostPolicy = autocert.HostWhitelist(*autoCertHostFlag)
}
srv := &http.Server{
Handler: h,
TLSConfig: &tls.Config{
GetCertificate: m.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))
}
// 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
}

81
vendor/golang.org/x/tools/cmd/godoc/blog.go generated vendored Normal file
View 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.
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(blogInit)
blogServer.ServeHTTP(w, r)
})
}
func blogInit() {
// 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,
})
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
View 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
View 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
View 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
View 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 }

489
vendor/golang.org/x/tools/cmd/godoc/godoc_test.go generated vendored Normal file
View File

@ -0,0 +1,489 @@
// 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"
cmd.Env = godocEnv()
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 = append(cmd.Env, fmt.Sprintf("GOROOT=%s", filepath.Join(tmpdir, "goroot")))
cmd.Env = append(cmd.Env, fmt.Sprintf("GOPATH=%s", filepath.Join(tmpdir, "gopath")))
for _, e := range os.Environ() {
if strings.HasPrefix(e, "GOROOT=") || strings.HasPrefix(e, "GOPATH=") {
continue
}
cmd.Env = append(cmd.Env, e)
}
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))
}
}
}
// godocEnv returns the process environment without the GOPATH variable.
// (We don't want the indexer looking at the local workspace during tests.)
func godocEnv() (env []string) {
for _, v := range os.Environ() {
if strings.HasPrefix(v, "GOPATH=") {
continue
}
env = append(env, v)
}
return
}

148
vendor/golang.org/x/tools/cmd/godoc/handlers.go generated vendored Normal file
View File

@ -0,0 +1,148 @@
// 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; 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.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
View 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/")
}

357
vendor/golang.org/x/tools/cmd/godoc/main.go generated vendored Normal file
View File

@ -0,0 +1,357 @@
// 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")
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", runtime.GOROOT(), "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()
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
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 serveAutoCertHook != nil {
go func() {
if err := serveAutoCertHook(handler); err != nil {
log.Fatalf("ListenAndServe TLS: %v", err)
}
}()
}
// Start http server.
if *verbose {
log.Println("starting HTTP server")
}
if err := http.ListenAndServe(*httpAddr, handler); err != nil {
log.Fatalf("ListenAndServe %s: %v", *httpAddr, err)
}
return
}
if *query {
handleRemoteSearch()
return
}
if err := godoc.CommandLine(os.Stdout, fs, pres, flag.Args()); err != nil {
log.Print(err)
}
}
// serveAutoCertHook if non-nil specifies a function to listen on port 443.
// See autocert.go.
var serveAutoCertHook func(http.Handler) error

11
vendor/golang.org/x/tools/cmd/godoc/play.go generated vendored Normal file
View 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
View 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
}

View 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
View 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"},
"arch": {"https://go.googlesource.com/arch", "git"},
"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"},
"mobile": {"https://go.googlesource.com/mobile", "git"},
"net": {"https://go.googlesource.com/net", "git"},
"oauth2": {"https://go.googlesource.com/oauth2", "git"},
"perf": {"https://go.googlesource.com/perf", "git"},
"playground": {"https://go.googlesource.com/playground", "git"},
"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"},
"term": {"https://go.googlesource.com/term", "git"},
"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"},
}
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>
`))

45
vendor/golang.org/x/tools/cmd/goimports/doc.go generated vendored Normal file
View File

@ -0,0 +1,45 @@
/*
Command goimports updates your Go import lines,
adding missing ones and removing unreferenced ones.
$ go get golang.org/x/tools/cmd/goimports
In addition to fixing imports, goimports also formats
your code in the same style as gofmt so it can be used
as a replacement for your editor's gofmt-on-save hook.
For emacs, make sure you have the latest go-mode.el:
https://github.com/dominikh/go-mode.el
Then in your .emacs file:
(setq gofmt-command "goimports")
(add-to-list 'load-path "/home/you/somewhere/emacs/")
(require 'go-mode-autoloads)
(add-hook 'before-save-hook 'gofmt-before-save)
For vim, set "gofmt_command" to "goimports":
https://golang.org/change/39c724dd7f252
https://golang.org/wiki/IDEsAndTextEditorPlugins
etc
For GoSublime, follow the steps described here:
http://michaelwhatcott.com/gosublime-goimports/
For other editors, you probably know what to do.
To exclude directories in your $GOPATH from being scanned for Go
files, goimports respects a configuration file at
$GOPATH/src/.goimportsignore which may contain blank lines, comment
lines (beginning with '#'), or lines naming a directory relative to
the configuration file to ignore when scanning. No globbing or regex
patterns are allowed. Use the "-v" verbose flag to verify it's
working and see what goimports is doing.
File bugs or feature requests at:
https://golang.org/issues/new?title=x/tools/cmd/goimports:+
Happy hacking!
*/
package main // import "golang.org/x/tools/cmd/goimports"

369
vendor/golang.org/x/tools/cmd/goimports/goimports.go generated vendored Normal file
View File

@ -0,0 +1,369 @@
// 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 (
"bufio"
"bytes"
"errors"
"flag"
"fmt"
"go/scanner"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"runtime/pprof"
"strings"
"golang.org/x/tools/imports"
)
var (
// main operation modes
list = flag.Bool("l", false, "list files whose formatting differs from goimport's")
write = flag.Bool("w", false, "write result to (source) file instead of stdout")
doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
srcdir = flag.String("srcdir", "", "choose imports as if source code is from `dir`. When operating on a single file, dir may instead be the complete file name.")
verbose bool // verbose logging
cpuProfile = flag.String("cpuprofile", "", "CPU profile output")
memProfile = flag.String("memprofile", "", "memory profile output")
memProfileRate = flag.Int("memrate", 0, "if > 0, sets runtime.MemProfileRate")
options = &imports.Options{
TabWidth: 8,
TabIndent: true,
Comments: true,
Fragment: true,
}
exitCode = 0
)
func init() {
flag.BoolVar(&options.AllErrors, "e", false, "report all errors (not just the first 10 on different lines)")
flag.StringVar(&imports.LocalPrefix, "local", "", "put imports beginning with this string after 3rd-party packages; comma-separated list")
}
func report(err error) {
scanner.PrintError(os.Stderr, err)
exitCode = 2
}
func usage() {
fmt.Fprintf(os.Stderr, "usage: goimports [flags] [path ...]\n")
flag.PrintDefaults()
os.Exit(2)
}
func isGoFile(f os.FileInfo) bool {
// ignore non-Go files
name := f.Name()
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}
// argumentType is which mode goimports was invoked as.
type argumentType int
const (
// fromStdin means the user is piping their source into goimports.
fromStdin argumentType = iota
// singleArg is the common case from editors, when goimports is run on
// a single file.
singleArg
// multipleArg is when the user ran "goimports file1.go file2.go"
// or ran goimports on a directory tree.
multipleArg
)
func processFile(filename string, in io.Reader, out io.Writer, argType argumentType) error {
opt := options
if argType == fromStdin {
nopt := *options
nopt.Fragment = true
opt = &nopt
}
if in == nil {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
in = f
}
src, err := ioutil.ReadAll(in)
if err != nil {
return err
}
target := filename
if *srcdir != "" {
// Determine whether the provided -srcdirc is a directory or file
// and then use it to override the target.
//
// See https://github.com/dominikh/go-mode.el/issues/146
if isFile(*srcdir) {
if argType == multipleArg {
return errors.New("-srcdir value can't be a file when passing multiple arguments or when walking directories")
}
target = *srcdir
} else if argType == singleArg && strings.HasSuffix(*srcdir, ".go") && !isDir(*srcdir) {
// For a file which doesn't exist on disk yet, but might shortly.
// e.g. user in editor opens $DIR/newfile.go and newfile.go doesn't yet exist on disk.
// The goimports on-save hook writes the buffer to a temp file
// first and runs goimports before the actual save to newfile.go.
// The editor's buffer is named "newfile.go" so that is passed to goimports as:
// goimports -srcdir=/gopath/src/pkg/newfile.go /tmp/gofmtXXXXXXXX.go
// and then the editor reloads the result from the tmp file and writes
// it to newfile.go.
target = *srcdir
} else {
// Pretend that file is from *srcdir in order to decide
// visible imports correctly.
target = filepath.Join(*srcdir, filepath.Base(filename))
}
}
res, err := imports.Process(target, src, opt)
if err != nil {
return err
}
if !bytes.Equal(src, res) {
// formatting has changed
if *list {
fmt.Fprintln(out, filename)
}
if *write {
if argType == fromStdin {
// filename is "<standard input>"
return errors.New("can't use -w on stdin")
}
err = ioutil.WriteFile(filename, res, 0)
if err != nil {
return err
}
}
if *doDiff {
if argType == fromStdin {
filename = "stdin.go" // because <standard input>.orig looks silly
}
data, err := diff(src, res, filename)
if err != nil {
return fmt.Errorf("computing diff: %s", err)
}
fmt.Printf("diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename))
out.Write(data)
}
}
if !*list && !*write && !*doDiff {
_, err = out.Write(res)
}
return err
}
func visitFile(path string, f os.FileInfo, err error) error {
if err == nil && isGoFile(f) {
err = processFile(path, nil, os.Stdout, multipleArg)
}
if err != nil {
report(err)
}
return nil
}
func walkDir(path string) {
filepath.Walk(path, visitFile)
}
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
// call gofmtMain in a separate function
// so that it can use defer and have them
// run before the exit.
gofmtMain()
os.Exit(exitCode)
}
// parseFlags parses command line flags and returns the paths to process.
// It's a var so that custom implementations can replace it in other files.
var parseFlags = func() []string {
flag.BoolVar(&verbose, "v", false, "verbose logging")
flag.Parse()
return flag.Args()
}
func bufferedFileWriter(dest string) (w io.Writer, close func()) {
f, err := os.Create(dest)
if err != nil {
log.Fatal(err)
}
bw := bufio.NewWriter(f)
return bw, func() {
if err := bw.Flush(); err != nil {
log.Fatalf("error flushing %v: %v", dest, err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
}
}
func gofmtMain() {
flag.Usage = usage
paths := parseFlags()
if *cpuProfile != "" {
bw, flush := bufferedFileWriter(*cpuProfile)
pprof.StartCPUProfile(bw)
defer flush()
defer pprof.StopCPUProfile()
}
// doTrace is a conditionally compiled wrapper around runtime/trace. It is
// used to allow goimports to compile under gccgo, which does not support
// runtime/trace. See https://golang.org/issue/15544.
defer doTrace()()
if *memProfileRate > 0 {
runtime.MemProfileRate = *memProfileRate
bw, flush := bufferedFileWriter(*memProfile)
defer func() {
runtime.GC() // materialize all statistics
if err := pprof.WriteHeapProfile(bw); err != nil {
log.Fatal(err)
}
flush()
}()
}
if verbose {
log.SetFlags(log.LstdFlags | log.Lmicroseconds)
imports.Debug = true
}
if options.TabWidth < 0 {
fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", options.TabWidth)
exitCode = 2
return
}
if len(paths) == 0 {
if err := processFile("<standard input>", os.Stdin, os.Stdout, fromStdin); err != nil {
report(err)
}
return
}
argType := singleArg
if len(paths) > 1 {
argType = multipleArg
}
for _, path := range paths {
switch dir, err := os.Stat(path); {
case err != nil:
report(err)
case dir.IsDir():
walkDir(path)
default:
if err := processFile(path, nil, os.Stdout, argType); err != nil {
report(err)
}
}
}
}
func writeTempFile(dir, prefix string, data []byte) (string, error) {
file, err := ioutil.TempFile(dir, prefix)
if err != nil {
return "", err
}
_, err = file.Write(data)
if err1 := file.Close(); err == nil {
err = err1
}
if err != nil {
os.Remove(file.Name())
return "", err
}
return file.Name(), nil
}
func diff(b1, b2 []byte, filename string) (data []byte, err error) {
f1, err := writeTempFile("", "gofmt", b1)
if err != nil {
return
}
defer os.Remove(f1)
f2, err := writeTempFile("", "gofmt", b2)
if err != nil {
return
}
defer os.Remove(f2)
cmd := "diff"
if runtime.GOOS == "plan9" {
cmd = "/bin/ape/diff"
}
data, err = exec.Command(cmd, "-u", f1, f2).CombinedOutput()
if len(data) > 0 {
// diff exits with a non-zero status when the files don't match.
// Ignore that failure as long as we get output.
return replaceTempFilename(data, filename)
}
return
}
// replaceTempFilename replaces temporary filenames in diff with actual one.
//
// --- /tmp/gofmt316145376 2017-02-03 19:13:00.280468375 -0500
// +++ /tmp/gofmt617882815 2017-02-03 19:13:00.280468375 -0500
// ...
// ->
// --- path/to/file.go.orig 2017-02-03 19:13:00.280468375 -0500
// +++ path/to/file.go 2017-02-03 19:13:00.280468375 -0500
// ...
func replaceTempFilename(diff []byte, filename string) ([]byte, error) {
bs := bytes.SplitN(diff, []byte{'\n'}, 3)
if len(bs) < 3 {
return nil, fmt.Errorf("got unexpected diff for %s", filename)
}
// Preserve timestamps.
var t0, t1 []byte
if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 {
t0 = bs[0][i:]
}
if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 {
t1 = bs[1][i:]
}
// Always print filepath with slash separator.
f := filepath.ToSlash(filename)
bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0))
bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1))
return bytes.Join(bs, []byte{'\n'}), nil
}
// isFile reports whether name is a file.
func isFile(name string) bool {
fi, err := os.Stat(name)
return err == nil && fi.Mode().IsRegular()
}
// isDir reports whether name is a directory.
func isDir(name string) bool {
fi, err := os.Stat(name)
return err == nil && fi.IsDir()
}

View File

@ -0,0 +1,26 @@
// 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 gc
package main
import (
"flag"
"runtime/trace"
)
var traceProfile = flag.String("trace", "", "trace profile output")
func doTrace() func() {
if *traceProfile != "" {
bw, flush := bufferedFileWriter(*traceProfile)
trace.Start(bw)
return func() {
flush()
trace.Stop()
}
}
return func() {}
}

View File

@ -0,0 +1,11 @@
// 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 !gc
package main
func doTrace() func() {
return func() {}
}

Some files were not shown because too many files have changed in this diff Show More