libgo: Add sources for go, cgo, and gofmt commands.
The new commands are not yet built. That will be done separately. Also include a few changes to go/build to support them. From-SVN: r219272
This commit is contained in:
parent
efcdb22fe3
commit
7d7d64c1ae
@ -26,6 +26,7 @@ STAMP = echo timestamp >
|
||||
toolexecdir = $(glibgo_toolexecdir)
|
||||
toolexeclibdir = $(glibgo_toolexeclibdir)
|
||||
toolexeclibgodir = $(nover_glibgo_toolexeclibdir)/go/$(gcc_version)/$(target_alias)
|
||||
libexecsubdir = $(libexecdir)/gcc/$(target_alias)/$(gcc_version)
|
||||
|
||||
LIBFFI = @LIBFFI@
|
||||
LIBFFIINCS = @LIBFFIINCS@
|
||||
@ -1007,6 +1008,7 @@ s-version: Makefile
|
||||
echo 'const theVersion = "'`$(GOC) --version | sed 1q`'"' >> version.go.tmp
|
||||
echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
|
||||
echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
|
||||
echo 'const theGccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
|
||||
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
|
||||
$(STAMP) $@
|
||||
|
||||
|
@ -454,6 +454,7 @@ STAMP = echo timestamp >
|
||||
toolexecdir = $(glibgo_toolexecdir)
|
||||
toolexeclibdir = $(glibgo_toolexeclibdir)
|
||||
toolexeclibgodir = $(nover_glibgo_toolexeclibdir)/go/$(gcc_version)/$(target_alias)
|
||||
libexecsubdir = $(libexecdir)/gcc/$(target_alias)/$(gcc_version)
|
||||
WARN_CFLAGS = $(WARN_FLAGS) $(WERROR)
|
||||
|
||||
# -I/-D flags to pass when compiling.
|
||||
@ -4392,6 +4393,7 @@ s-version: Makefile
|
||||
echo 'const theVersion = "'`$(GOC) --version | sed 1q`'"' >> version.go.tmp
|
||||
echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
|
||||
echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
|
||||
echo 'const theGccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
|
||||
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
|
||||
$(STAMP) $@
|
||||
|
||||
|
460
libgo/go/cmd/cgo/ast.go
Normal file
460
libgo/go/cmd/cgo/ast.go
Normal file
@ -0,0 +1,460 @@
|
||||
// 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.
|
||||
|
||||
// Parse input AST and prepare Prog structure.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parse(name string, flags parser.Mode) *ast.File {
|
||||
ast1, err := parser.ParseFile(fset, name, nil, flags)
|
||||
if err != nil {
|
||||
if list, ok := err.(scanner.ErrorList); ok {
|
||||
// If err is a scanner.ErrorList, its String will print just
|
||||
// the first error and then (+n more errors).
|
||||
// Instead, turn it into a new Error that will return
|
||||
// details for all the errors.
|
||||
for _, e := range list {
|
||||
fmt.Fprintln(os.Stderr, e)
|
||||
}
|
||||
os.Exit(2)
|
||||
}
|
||||
fatalf("parsing %s: %s", name, err)
|
||||
}
|
||||
return ast1
|
||||
}
|
||||
|
||||
func sourceLine(n ast.Node) int {
|
||||
return fset.Position(n.Pos()).Line
|
||||
}
|
||||
|
||||
// ReadGo populates f with information learned from reading the
|
||||
// Go source file with the given file name. It gathers the C preamble
|
||||
// attached to the import "C" comment, a list of references to C.xxx,
|
||||
// a list of exported functions, and the actual AST, to be rewritten and
|
||||
// printed.
|
||||
func (f *File) ReadGo(name string) {
|
||||
// Create absolute path for file, so that it will be used in error
|
||||
// messages and recorded in debug line number information.
|
||||
// This matches the rest of the toolchain. See golang.org/issue/5122.
|
||||
if aname, err := filepath.Abs(name); err == nil {
|
||||
name = aname
|
||||
}
|
||||
|
||||
// Two different parses: once with comments, once without.
|
||||
// The printer is not good enough at printing comments in the
|
||||
// right place when we start editing the AST behind its back,
|
||||
// so we use ast1 to look for the doc comments on import "C"
|
||||
// and on exported functions, and we use ast2 for translating
|
||||
// and reprinting.
|
||||
ast1 := parse(name, parser.ParseComments)
|
||||
ast2 := parse(name, 0)
|
||||
|
||||
f.Package = ast1.Name.Name
|
||||
f.Name = make(map[string]*Name)
|
||||
|
||||
// In ast1, find the import "C" line and get any extra C preamble.
|
||||
sawC := false
|
||||
for _, decl := range ast1.Decls {
|
||||
d, ok := decl.(*ast.GenDecl)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, spec := range d.Specs {
|
||||
s, ok := spec.(*ast.ImportSpec)
|
||||
if !ok || string(s.Path.Value) != `"C"` {
|
||||
continue
|
||||
}
|
||||
sawC = true
|
||||
if s.Name != nil {
|
||||
error_(s.Path.Pos(), `cannot rename import "C"`)
|
||||
}
|
||||
cg := s.Doc
|
||||
if cg == nil && len(d.Specs) == 1 {
|
||||
cg = d.Doc
|
||||
}
|
||||
if cg != nil {
|
||||
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
|
||||
f.Preamble += commentText(cg) + "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
if !sawC {
|
||||
error_(token.NoPos, `cannot find import "C"`)
|
||||
}
|
||||
|
||||
// In ast2, strip the import "C" line.
|
||||
w := 0
|
||||
for _, decl := range ast2.Decls {
|
||||
d, ok := decl.(*ast.GenDecl)
|
||||
if !ok {
|
||||
ast2.Decls[w] = decl
|
||||
w++
|
||||
continue
|
||||
}
|
||||
ws := 0
|
||||
for _, spec := range d.Specs {
|
||||
s, ok := spec.(*ast.ImportSpec)
|
||||
if !ok || string(s.Path.Value) != `"C"` {
|
||||
d.Specs[ws] = spec
|
||||
ws++
|
||||
}
|
||||
}
|
||||
if ws == 0 {
|
||||
continue
|
||||
}
|
||||
d.Specs = d.Specs[0:ws]
|
||||
ast2.Decls[w] = d
|
||||
w++
|
||||
}
|
||||
ast2.Decls = ast2.Decls[0:w]
|
||||
|
||||
// Accumulate pointers to uses of C.x.
|
||||
if f.Ref == nil {
|
||||
f.Ref = make([]*Ref, 0, 8)
|
||||
}
|
||||
f.walk(ast2, "prog", (*File).saveRef)
|
||||
|
||||
// Accumulate exported functions.
|
||||
// The comments are only on ast1 but we need to
|
||||
// save the function bodies from ast2.
|
||||
// The first walk fills in ExpFunc, and the
|
||||
// second walk changes the entries to
|
||||
// refer to ast2 instead.
|
||||
f.walk(ast1, "prog", (*File).saveExport)
|
||||
f.walk(ast2, "prog", (*File).saveExport2)
|
||||
|
||||
f.Comments = ast1.Comments
|
||||
f.AST = ast2
|
||||
}
|
||||
|
||||
// Like ast.CommentGroup's Text method but preserves
|
||||
// leading blank lines, so that line numbers line up.
|
||||
func commentText(g *ast.CommentGroup) string {
|
||||
if g == nil {
|
||||
return ""
|
||||
}
|
||||
var pieces []string
|
||||
for _, com := range g.List {
|
||||
c := string(com.Text)
|
||||
// Remove comment markers.
|
||||
// The parser has given us exactly the comment text.
|
||||
switch c[1] {
|
||||
case '/':
|
||||
//-style comment (no newline at the end)
|
||||
c = c[2:] + "\n"
|
||||
case '*':
|
||||
/*-style comment */
|
||||
c = c[2 : len(c)-2]
|
||||
}
|
||||
pieces = append(pieces, c)
|
||||
}
|
||||
return strings.Join(pieces, "")
|
||||
}
|
||||
|
||||
// Save references to C.xxx for later processing.
|
||||
func (f *File) saveRef(x interface{}, context string) {
|
||||
n, ok := x.(*ast.Expr)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if sel, ok := (*n).(*ast.SelectorExpr); ok {
|
||||
// For now, assume that the only instance of capital C is
|
||||
// when used as the imported package identifier.
|
||||
// The parser should take care of scoping in the future,
|
||||
// so that we will be able to distinguish a "top-level C"
|
||||
// from a local C.
|
||||
if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" {
|
||||
if context == "as2" {
|
||||
context = "expr"
|
||||
}
|
||||
if context == "embed-type" {
|
||||
error_(sel.Pos(), "cannot embed C type")
|
||||
}
|
||||
goname := sel.Sel.Name
|
||||
if goname == "errno" {
|
||||
error_(sel.Pos(), "cannot refer to errno directly; see documentation")
|
||||
return
|
||||
}
|
||||
if goname == "_CMalloc" {
|
||||
error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc")
|
||||
return
|
||||
}
|
||||
if goname == "malloc" {
|
||||
goname = "_CMalloc"
|
||||
}
|
||||
name := f.Name[goname]
|
||||
if name == nil {
|
||||
name = &Name{
|
||||
Go: goname,
|
||||
}
|
||||
f.Name[goname] = name
|
||||
}
|
||||
f.Ref = append(f.Ref, &Ref{
|
||||
Name: name,
|
||||
Expr: n,
|
||||
Context: context,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If a function should be exported add it to ExpFunc.
|
||||
func (f *File) saveExport(x interface{}, context string) {
|
||||
n, ok := x.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if n.Doc == nil {
|
||||
return
|
||||
}
|
||||
for _, c := range n.Doc.List {
|
||||
if !strings.HasPrefix(string(c.Text), "//export ") {
|
||||
continue
|
||||
}
|
||||
|
||||
name := strings.TrimSpace(string(c.Text[9:]))
|
||||
if name == "" {
|
||||
error_(c.Pos(), "export missing name")
|
||||
}
|
||||
|
||||
if name != n.Name.Name {
|
||||
error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
|
||||
}
|
||||
|
||||
f.ExpFunc = append(f.ExpFunc, &ExpFunc{
|
||||
Func: n,
|
||||
ExpName: name,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Make f.ExpFunc[i] point at the Func from this AST instead of the other one.
|
||||
func (f *File) saveExport2(x interface{}, context string) {
|
||||
n, ok := x.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for _, exp := range f.ExpFunc {
|
||||
if exp.Func.Name.Name == n.Name.Name {
|
||||
exp.Func = n
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// walk walks the AST x, calling visit(f, x, context) for each node.
|
||||
func (f *File) walk(x interface{}, context string, visit func(*File, interface{}, string)) {
|
||||
visit(f, x, context)
|
||||
switch n := x.(type) {
|
||||
case *ast.Expr:
|
||||
f.walk(*n, context, visit)
|
||||
|
||||
// everything else just recurs
|
||||
default:
|
||||
error_(token.NoPos, "unexpected type %T in walk", x, visit)
|
||||
panic("unexpected type")
|
||||
|
||||
case nil:
|
||||
|
||||
// These are ordered and grouped to match ../../pkg/go/ast/ast.go
|
||||
case *ast.Field:
|
||||
if len(n.Names) == 0 && context == "field" {
|
||||
f.walk(&n.Type, "embed-type", visit)
|
||||
} else {
|
||||
f.walk(&n.Type, "type", visit)
|
||||
}
|
||||
case *ast.FieldList:
|
||||
for _, field := range n.List {
|
||||
f.walk(field, context, visit)
|
||||
}
|
||||
case *ast.BadExpr:
|
||||
case *ast.Ident:
|
||||
case *ast.Ellipsis:
|
||||
case *ast.BasicLit:
|
||||
case *ast.FuncLit:
|
||||
f.walk(n.Type, "type", visit)
|
||||
f.walk(n.Body, "stmt", visit)
|
||||
case *ast.CompositeLit:
|
||||
f.walk(&n.Type, "type", visit)
|
||||
f.walk(n.Elts, "expr", visit)
|
||||
case *ast.ParenExpr:
|
||||
f.walk(&n.X, context, visit)
|
||||
case *ast.SelectorExpr:
|
||||
f.walk(&n.X, "selector", visit)
|
||||
case *ast.IndexExpr:
|
||||
f.walk(&n.X, "expr", visit)
|
||||
f.walk(&n.Index, "expr", visit)
|
||||
case *ast.SliceExpr:
|
||||
f.walk(&n.X, "expr", visit)
|
||||
if n.Low != nil {
|
||||
f.walk(&n.Low, "expr", visit)
|
||||
}
|
||||
if n.High != nil {
|
||||
f.walk(&n.High, "expr", visit)
|
||||
}
|
||||
case *ast.TypeAssertExpr:
|
||||
f.walk(&n.X, "expr", visit)
|
||||
f.walk(&n.Type, "type", visit)
|
||||
case *ast.CallExpr:
|
||||
if context == "as2" {
|
||||
f.walk(&n.Fun, "call2", visit)
|
||||
} else {
|
||||
f.walk(&n.Fun, "call", visit)
|
||||
}
|
||||
f.walk(n.Args, "expr", visit)
|
||||
case *ast.StarExpr:
|
||||
f.walk(&n.X, context, visit)
|
||||
case *ast.UnaryExpr:
|
||||
f.walk(&n.X, "expr", visit)
|
||||
case *ast.BinaryExpr:
|
||||
f.walk(&n.X, "expr", visit)
|
||||
f.walk(&n.Y, "expr", visit)
|
||||
case *ast.KeyValueExpr:
|
||||
f.walk(&n.Key, "expr", visit)
|
||||
f.walk(&n.Value, "expr", visit)
|
||||
|
||||
case *ast.ArrayType:
|
||||
f.walk(&n.Len, "expr", visit)
|
||||
f.walk(&n.Elt, "type", visit)
|
||||
case *ast.StructType:
|
||||
f.walk(n.Fields, "field", visit)
|
||||
case *ast.FuncType:
|
||||
f.walk(n.Params, "param", visit)
|
||||
if n.Results != nil {
|
||||
f.walk(n.Results, "param", visit)
|
||||
}
|
||||
case *ast.InterfaceType:
|
||||
f.walk(n.Methods, "field", visit)
|
||||
case *ast.MapType:
|
||||
f.walk(&n.Key, "type", visit)
|
||||
f.walk(&n.Value, "type", visit)
|
||||
case *ast.ChanType:
|
||||
f.walk(&n.Value, "type", visit)
|
||||
|
||||
case *ast.BadStmt:
|
||||
case *ast.DeclStmt:
|
||||
f.walk(n.Decl, "decl", visit)
|
||||
case *ast.EmptyStmt:
|
||||
case *ast.LabeledStmt:
|
||||
f.walk(n.Stmt, "stmt", visit)
|
||||
case *ast.ExprStmt:
|
||||
f.walk(&n.X, "expr", visit)
|
||||
case *ast.SendStmt:
|
||||
f.walk(&n.Chan, "expr", visit)
|
||||
f.walk(&n.Value, "expr", visit)
|
||||
case *ast.IncDecStmt:
|
||||
f.walk(&n.X, "expr", visit)
|
||||
case *ast.AssignStmt:
|
||||
f.walk(n.Lhs, "expr", visit)
|
||||
if len(n.Lhs) == 2 && len(n.Rhs) == 1 {
|
||||
f.walk(n.Rhs, "as2", visit)
|
||||
} else {
|
||||
f.walk(n.Rhs, "expr", visit)
|
||||
}
|
||||
case *ast.GoStmt:
|
||||
f.walk(n.Call, "expr", visit)
|
||||
case *ast.DeferStmt:
|
||||
f.walk(n.Call, "expr", visit)
|
||||
case *ast.ReturnStmt:
|
||||
f.walk(n.Results, "expr", visit)
|
||||
case *ast.BranchStmt:
|
||||
case *ast.BlockStmt:
|
||||
f.walk(n.List, context, visit)
|
||||
case *ast.IfStmt:
|
||||
f.walk(n.Init, "stmt", visit)
|
||||
f.walk(&n.Cond, "expr", visit)
|
||||
f.walk(n.Body, "stmt", visit)
|
||||
f.walk(n.Else, "stmt", visit)
|
||||
case *ast.CaseClause:
|
||||
if context == "typeswitch" {
|
||||
context = "type"
|
||||
} else {
|
||||
context = "expr"
|
||||
}
|
||||
f.walk(n.List, context, visit)
|
||||
f.walk(n.Body, "stmt", visit)
|
||||
case *ast.SwitchStmt:
|
||||
f.walk(n.Init, "stmt", visit)
|
||||
f.walk(&n.Tag, "expr", visit)
|
||||
f.walk(n.Body, "switch", visit)
|
||||
case *ast.TypeSwitchStmt:
|
||||
f.walk(n.Init, "stmt", visit)
|
||||
f.walk(n.Assign, "stmt", visit)
|
||||
f.walk(n.Body, "typeswitch", visit)
|
||||
case *ast.CommClause:
|
||||
f.walk(n.Comm, "stmt", visit)
|
||||
f.walk(n.Body, "stmt", visit)
|
||||
case *ast.SelectStmt:
|
||||
f.walk(n.Body, "stmt", visit)
|
||||
case *ast.ForStmt:
|
||||
f.walk(n.Init, "stmt", visit)
|
||||
f.walk(&n.Cond, "expr", visit)
|
||||
f.walk(n.Post, "stmt", visit)
|
||||
f.walk(n.Body, "stmt", visit)
|
||||
case *ast.RangeStmt:
|
||||
f.walk(&n.Key, "expr", visit)
|
||||
f.walk(&n.Value, "expr", visit)
|
||||
f.walk(&n.X, "expr", visit)
|
||||
f.walk(n.Body, "stmt", visit)
|
||||
|
||||
case *ast.ImportSpec:
|
||||
case *ast.ValueSpec:
|
||||
f.walk(&n.Type, "type", visit)
|
||||
f.walk(n.Values, "expr", visit)
|
||||
case *ast.TypeSpec:
|
||||
f.walk(&n.Type, "type", visit)
|
||||
|
||||
case *ast.BadDecl:
|
||||
case *ast.GenDecl:
|
||||
f.walk(n.Specs, "spec", visit)
|
||||
case *ast.FuncDecl:
|
||||
if n.Recv != nil {
|
||||
f.walk(n.Recv, "param", visit)
|
||||
}
|
||||
f.walk(n.Type, "type", visit)
|
||||
if n.Body != nil {
|
||||
f.walk(n.Body, "stmt", visit)
|
||||
}
|
||||
|
||||
case *ast.File:
|
||||
f.walk(n.Decls, "decl", visit)
|
||||
|
||||
case *ast.Package:
|
||||
for _, file := range n.Files {
|
||||
f.walk(file, "file", visit)
|
||||
}
|
||||
|
||||
case []ast.Decl:
|
||||
for _, d := range n {
|
||||
f.walk(d, context, visit)
|
||||
}
|
||||
case []ast.Expr:
|
||||
for i := range n {
|
||||
f.walk(&n[i], context, visit)
|
||||
}
|
||||
case []ast.Stmt:
|
||||
for _, s := range n {
|
||||
f.walk(s, context, visit)
|
||||
}
|
||||
case []ast.Spec:
|
||||
for _, s := range n {
|
||||
f.walk(s, context, visit)
|
||||
}
|
||||
}
|
||||
}
|
748
libgo/go/cmd/cgo/doc.go
Normal file
748
libgo/go/cmd/cgo/doc.go
Normal file
@ -0,0 +1,748 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
|
||||
Cgo enables the creation of Go packages that call C code.
|
||||
|
||||
Using cgo with the go command
|
||||
|
||||
To use cgo write normal Go code that imports a pseudo-package "C".
|
||||
The Go code can then refer to types such as C.size_t, variables such
|
||||
as C.stdout, or functions such as C.putchar.
|
||||
|
||||
If the import of "C" is immediately preceded by a comment, that
|
||||
comment, called the preamble, is used as a header when compiling
|
||||
the C parts of the package. For example:
|
||||
|
||||
// #include <stdio.h>
|
||||
// #include <errno.h>
|
||||
import "C"
|
||||
|
||||
See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples. See
|
||||
"C? Go? Cgo!" for an introduction to using cgo:
|
||||
http://golang.org/doc/articles/c_go_cgo.html.
|
||||
|
||||
CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS may be defined with pseudo #cgo
|
||||
directives within these comments to tweak the behavior of the C or C++
|
||||
compiler. Values defined in multiple directives are concatenated
|
||||
together. The directive can include a list of build constraints limiting its
|
||||
effect to systems satisfying one of the constraints
|
||||
(see http://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax).
|
||||
For example:
|
||||
|
||||
// #cgo CFLAGS: -DPNG_DEBUG=1
|
||||
// #cgo amd64 386 CFLAGS: -DX86=1
|
||||
// #cgo LDFLAGS: -lpng
|
||||
// #include <png.h>
|
||||
import "C"
|
||||
|
||||
Alternatively, CPPFLAGS and LDFLAGS may be obtained via the pkg-config
|
||||
tool using a '#cgo pkg-config:' directive followed by the package names.
|
||||
For example:
|
||||
|
||||
// #cgo pkg-config: png cairo
|
||||
// #include <png.h>
|
||||
import "C"
|
||||
|
||||
When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS and
|
||||
CGO_LDFLAGS environment variables are added to the flags derived from
|
||||
these directives. Package-specific flags should be set using the
|
||||
directives, not the environment variables, so that builds work in
|
||||
unmodified environments.
|
||||
|
||||
All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and
|
||||
used to compile C files in that package. All the CPPFLAGS and CXXFLAGS
|
||||
directives in a package are concatenated and used to compile C++ files in that
|
||||
package. All the LDFLAGS directives in any package in the program are
|
||||
concatenated and used at link time. All the pkg-config directives are
|
||||
concatenated and sent to pkg-config simultaneously to add to each appropriate
|
||||
set of command-line flags.
|
||||
|
||||
When the Go tool sees that one or more Go files use the special import
|
||||
"C", it will look for other non-Go files in the directory and compile
|
||||
them as part of the Go package. Any .c, .s, or .S files will be
|
||||
compiled with the C compiler. Any .cc, .cpp, or .cxx files will be
|
||||
compiled with the C++ compiler. Any .h, .hh, .hpp, or .hxx files will
|
||||
not be compiled separately, but, if these header files are changed,
|
||||
the C and C++ files will be recompiled. The default C and C++
|
||||
compilers may be changed by the CC and CXX environment variables,
|
||||
respectively; those environment variables may include command line
|
||||
options.
|
||||
|
||||
To enable cgo during cross compiling builds, set the CGO_ENABLED
|
||||
environment variable to 1 when building the Go tools with make.bash.
|
||||
Also, set CC_FOR_TARGET to the C cross compiler for the target. CC will
|
||||
be used for compiling for the host.
|
||||
|
||||
After the Go tools are built, when running the go command, CC_FOR_TARGET is
|
||||
ignored. The value of CC_FOR_TARGET when running make.bash is the default
|
||||
compiler. However, you can set the environment variable CC, not CC_FOR_TARGET,
|
||||
to control the compiler when running the go tool.
|
||||
|
||||
CXX_FOR_TARGET works in a similar way for C++ code.
|
||||
|
||||
Go references to C
|
||||
|
||||
Within the Go file, C's struct field names that are keywords in Go
|
||||
can be accessed by prefixing them with an underscore: if x points at a C
|
||||
struct with a field named "type", x._type accesses the field.
|
||||
C struct fields that cannot be expressed in Go, such as bit fields
|
||||
or misaligned data, are omitted in the Go struct, replaced by
|
||||
appropriate padding to reach the next field or the end of the struct.
|
||||
|
||||
The standard C numeric types are available under the names
|
||||
C.char, C.schar (signed char), C.uchar (unsigned char),
|
||||
C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
|
||||
C.long, C.ulong (unsigned long), C.longlong (long long),
|
||||
C.ulonglong (unsigned long long), C.float, C.double.
|
||||
The C type void* is represented by Go's unsafe.Pointer.
|
||||
|
||||
To access a struct, union, or enum type directly, prefix it with
|
||||
struct_, union_, or enum_, as in C.struct_stat.
|
||||
|
||||
As Go doesn't have support for C's union type in the general case,
|
||||
C's union types are represented as a Go byte array with the same length.
|
||||
|
||||
Go structs cannot embed fields with C types.
|
||||
|
||||
Cgo translates C types into equivalent unexported Go types.
|
||||
Because the translations are unexported, a Go package should not
|
||||
expose C types in its exported API: a C type used in one Go package
|
||||
is different from the same C type used in another.
|
||||
|
||||
Any C function (even void functions) may be called in a multiple
|
||||
assignment context to retrieve both the return value (if any) and the
|
||||
C errno variable as an error (use _ to skip the result value if the
|
||||
function returns void). For example:
|
||||
|
||||
n, err := C.sqrt(-1)
|
||||
_, err := C.voidFunc()
|
||||
|
||||
Calling C function pointers is currently not supported, however you can
|
||||
declare Go variables which hold C function pointers and pass them
|
||||
back and forth between Go and C. C code may call function pointers
|
||||
received from Go. For example:
|
||||
|
||||
package main
|
||||
|
||||
// typedef int (*intFunc) ();
|
||||
//
|
||||
// int
|
||||
// bridge_int_func(intFunc f)
|
||||
// {
|
||||
// return f();
|
||||
// }
|
||||
//
|
||||
// int fortytwo()
|
||||
// {
|
||||
// return 42;
|
||||
// }
|
||||
import "C"
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
f := C.intFunc(C.fortytwo)
|
||||
fmt.Println(int(C.bridge_int_func(f)))
|
||||
// Output: 42
|
||||
}
|
||||
|
||||
In C, a function argument written as a fixed size array
|
||||
actually requires a pointer to the first element of the array.
|
||||
C compilers are aware of this calling convention and adjust
|
||||
the call accordingly, but Go cannot. In Go, you must pass
|
||||
the pointer to the first element explicitly: C.f(&x[0]).
|
||||
|
||||
A few special functions convert between Go and C types
|
||||
by making copies of the data. In pseudo-Go definitions:
|
||||
|
||||
// Go string to C string
|
||||
// The C string is allocated in the C heap using malloc.
|
||||
// It is the caller's responsibility to arrange for it to be
|
||||
// freed, such as by calling C.free (be sure to include stdlib.h
|
||||
// if C.free is needed).
|
||||
func C.CString(string) *C.char
|
||||
|
||||
// C string to Go string
|
||||
func C.GoString(*C.char) string
|
||||
|
||||
// C string, length to Go string
|
||||
func C.GoStringN(*C.char, C.int) string
|
||||
|
||||
// C pointer, length to Go []byte
|
||||
func C.GoBytes(unsafe.Pointer, C.int) []byte
|
||||
|
||||
C references to Go
|
||||
|
||||
Go functions can be exported for use by C code in the following way:
|
||||
|
||||
//export MyFunction
|
||||
func MyFunction(arg1, arg2 int, arg3 string) int64 {...}
|
||||
|
||||
//export MyFunction2
|
||||
func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...}
|
||||
|
||||
They will be available in the C code as:
|
||||
|
||||
extern int64 MyFunction(int arg1, int arg2, GoString arg3);
|
||||
extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);
|
||||
|
||||
found in the _cgo_export.h generated header, after any preambles
|
||||
copied from the cgo input files. Functions with multiple
|
||||
return values are mapped to functions returning a struct.
|
||||
Not all Go types can be mapped to C types in a useful way.
|
||||
|
||||
Using //export in a file places a restriction on the preamble:
|
||||
since it is copied into two different C output files, it must not
|
||||
contain any definitions, only declarations. Definitions must be
|
||||
placed in preambles in other files, or in C source files.
|
||||
|
||||
Using cgo directly
|
||||
|
||||
Usage:
|
||||
go tool cgo [cgo options] [-- compiler options] file.go
|
||||
|
||||
Cgo transforms the input file.go into four output files: two Go source
|
||||
files, a C file for 6c (or 8c or 5c), and a C file for gcc.
|
||||
|
||||
The compiler options are passed through uninterpreted when
|
||||
invoking the C compiler to compile the C parts of the package.
|
||||
|
||||
The following options are available when running cgo directly:
|
||||
|
||||
-dynimport file
|
||||
Write list of symbols imported by file. Write to
|
||||
-dynout argument or to standard output. Used by go
|
||||
build when building a cgo package.
|
||||
-dynout file
|
||||
Write -dynimport output to file.
|
||||
-dynlinker
|
||||
Write dynamic linker as part of -dynimport output.
|
||||
-godefs
|
||||
Write out input file in Go syntax replacing C package
|
||||
names with real values. Used to generate files in the
|
||||
syscall package when bootstrapping a new target.
|
||||
-cdefs
|
||||
Like -godefs, but write file in C syntax.
|
||||
Used to generate files in the runtime package when
|
||||
bootstrapping a new target.
|
||||
-objdir directory
|
||||
Put all generated files in directory.
|
||||
-gccgo
|
||||
Generate output for the gccgo compiler rather than the
|
||||
gc compiler.
|
||||
-gccgoprefix prefix
|
||||
The -fgo-prefix option to be used with gccgo.
|
||||
-gccgopkgpath path
|
||||
The -fgo-pkgpath option to be used with gccgo.
|
||||
-import_runtime_cgo
|
||||
If set (which it is by default) import runtime/cgo in
|
||||
generated output.
|
||||
-import_syscall
|
||||
If set (which it is by default) import syscall in
|
||||
generated output.
|
||||
-debug-define
|
||||
Debugging option. Print #defines.
|
||||
-debug-gcc
|
||||
Debugging option. Trace C compiler execution and output.
|
||||
*/
|
||||
package main
|
||||
|
||||
/*
|
||||
Implementation details.
|
||||
|
||||
Cgo provides a way for Go programs to call C code linked into the same
|
||||
address space. This comment explains the operation of cgo.
|
||||
|
||||
Cgo reads a set of Go source files and looks for statements saying
|
||||
import "C". If the import has a doc comment, that comment is
|
||||
taken as literal C code to be used as a preamble to any C code
|
||||
generated by cgo. A typical preamble #includes necessary definitions:
|
||||
|
||||
// #include <stdio.h>
|
||||
import "C"
|
||||
|
||||
For more details about the usage of cgo, see the documentation
|
||||
comment at the top of this file.
|
||||
|
||||
Understanding C
|
||||
|
||||
Cgo scans the Go source files that import "C" for uses of that
|
||||
package, such as C.puts. It collects all such identifiers. The next
|
||||
step is to determine each kind of name. In C.xxx the xxx might refer
|
||||
to a type, a function, a constant, or a global variable. Cgo must
|
||||
decide which.
|
||||
|
||||
The obvious thing for cgo to do is to process the preamble, expanding
|
||||
#includes and processing the corresponding C code. That would require
|
||||
a full C parser and type checker that was also aware of any extensions
|
||||
known to the system compiler (for example, all the GNU C extensions) as
|
||||
well as the system-specific header locations and system-specific
|
||||
pre-#defined macros. This is certainly possible to do, but it is an
|
||||
enormous amount of work.
|
||||
|
||||
Cgo takes a different approach. It determines the meaning of C
|
||||
identifiers not by parsing C code but by feeding carefully constructed
|
||||
programs into the system C compiler and interpreting the generated
|
||||
error messages, debug information, and object files. In practice,
|
||||
parsing these is significantly less work and more robust than parsing
|
||||
C source.
|
||||
|
||||
Cgo first invokes gcc -E -dM on the preamble, in order to find out
|
||||
about simple #defines for constants and the like. These are recorded
|
||||
for later use.
|
||||
|
||||
Next, cgo needs to identify the kinds for each identifier. For the
|
||||
identifiers C.foo and C.bar, cgo generates this C program:
|
||||
|
||||
<preamble>
|
||||
#line 1 "not-declared"
|
||||
void __cgo_f_xxx_1(void) { __typeof__(foo) *__cgo_undefined__; }
|
||||
#line 1 "not-type"
|
||||
void __cgo_f_xxx_2(void) { foo *__cgo_undefined__; }
|
||||
#line 1 "not-const"
|
||||
void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (foo)*1 }; }
|
||||
#line 2 "not-declared"
|
||||
void __cgo_f_xxx_1(void) { __typeof__(bar) *__cgo_undefined__; }
|
||||
#line 2 "not-type"
|
||||
void __cgo_f_xxx_2(void) { bar *__cgo_undefined__; }
|
||||
#line 2 "not-const"
|
||||
void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (bar)*1 }; }
|
||||
|
||||
This program will not compile, but cgo can use the presence or absence
|
||||
of an error message on a given line to deduce the information it
|
||||
needs. The program is syntactically valid regardless of whether each
|
||||
name is a type or an ordinary identifier, so there will be no syntax
|
||||
errors that might stop parsing early.
|
||||
|
||||
An error on not-declared:1 indicates that foo is undeclared.
|
||||
An error on not-type:1 indicates that foo is not a type (if declared at all, it is an identifier).
|
||||
An error on not-const:1 indicates that foo is not an integer constant.
|
||||
|
||||
The line number specifies the name involved. In the example, 1 is foo and 2 is bar.
|
||||
|
||||
Next, cgo must learn the details of each type, variable, function, or
|
||||
constant. It can do this by reading object files. If cgo has decided
|
||||
that t1 is a type, v2 and v3 are variables or functions, and c4, c5,
|
||||
and c6 are constants, it generates:
|
||||
|
||||
<preamble>
|
||||
__typeof__(t1) *__cgo__1;
|
||||
__typeof__(v2) *__cgo__2;
|
||||
__typeof__(v3) *__cgo__3;
|
||||
__typeof__(c4) *__cgo__4;
|
||||
enum { __cgo_enum__4 = c4 };
|
||||
__typeof__(c5) *__cgo__5;
|
||||
enum { __cgo_enum__5 = c5 };
|
||||
__typeof__(c6) *__cgo__6;
|
||||
enum { __cgo_enum__6 = c6 };
|
||||
|
||||
long long __cgo_debug_data[] = {
|
||||
0, // t1
|
||||
0, // v2
|
||||
0, // v3
|
||||
c4,
|
||||
c5,
|
||||
c6,
|
||||
1
|
||||
};
|
||||
|
||||
and again invokes the system C compiler, to produce an object file
|
||||
containing debug information. Cgo parses the DWARF debug information
|
||||
for __cgo__N to learn the type of each identifier. (The types also
|
||||
distinguish functions from global variables.) If using a standard gcc,
|
||||
cgo can parse the DWARF debug information for the __cgo_enum__N to
|
||||
learn the identifier's value. The LLVM-based gcc on OS X emits
|
||||
incomplete DWARF information for enums; in that case cgo reads the
|
||||
constant values from the __cgo_debug_data from the object file's data
|
||||
segment.
|
||||
|
||||
At this point cgo knows the meaning of each C.xxx well enough to start
|
||||
the translation process.
|
||||
|
||||
Translating Go
|
||||
|
||||
[The rest of this comment refers to 6g and 6c, the Go and C compilers
|
||||
that are part of the amd64 port of the gc Go toolchain. Everything here
|
||||
applies to another architecture's compilers as well.]
|
||||
|
||||
Given the input Go files x.go and y.go, cgo generates these source
|
||||
files:
|
||||
|
||||
x.cgo1.go # for 6g
|
||||
y.cgo1.go # for 6g
|
||||
_cgo_gotypes.go # for 6g
|
||||
_cgo_defun.c # for 6c
|
||||
x.cgo2.c # for gcc
|
||||
y.cgo2.c # for gcc
|
||||
_cgo_export.c # for gcc
|
||||
_cgo_main.c # for gcc
|
||||
|
||||
The file x.cgo1.go is a copy of x.go with the import "C" removed and
|
||||
references to C.xxx replaced with names like _Cfunc_xxx or _Ctype_xxx.
|
||||
The definitions of those identifiers, written as Go functions, types,
|
||||
or variables, are provided in _cgo_gotypes.go.
|
||||
|
||||
Here is a _cgo_gotypes.go containing definitions for C.flush (provided
|
||||
in the preamble) and C.puts (from stdio):
|
||||
|
||||
type _Ctype_char int8
|
||||
type _Ctype_int int32
|
||||
type _Ctype_void [0]byte
|
||||
|
||||
func _Cfunc_CString(string) *_Ctype_char
|
||||
func _Cfunc_flush() _Ctype_void
|
||||
func _Cfunc_puts(*_Ctype_char) _Ctype_int
|
||||
|
||||
For functions, cgo only writes an external declaration in the Go
|
||||
output. The implementation is in a combination of C for 6c (meaning
|
||||
any gc-toolchain compiler) and C for gcc.
|
||||
|
||||
The 6c file contains the definitions of the functions. They all have
|
||||
similar bodies that invoke runtime·cgocall to make a switch from the
|
||||
Go runtime world to the system C (GCC-based) world.
|
||||
|
||||
For example, here is the definition of _Cfunc_puts:
|
||||
|
||||
void _cgo_be59f0f25121_Cfunc_puts(void*);
|
||||
|
||||
void
|
||||
·_Cfunc_puts(struct{uint8 x[1];}p)
|
||||
{
|
||||
runtime·cgocall(_cgo_be59f0f25121_Cfunc_puts, &p);
|
||||
}
|
||||
|
||||
The hexadecimal number is a hash of cgo's input, chosen to be
|
||||
deterministic yet unlikely to collide with other uses. The actual
|
||||
function _cgo_be59f0f25121_Cfunc_puts is implemented in a C source
|
||||
file compiled by gcc, the file x.cgo2.c:
|
||||
|
||||
void
|
||||
_cgo_be59f0f25121_Cfunc_puts(void *v)
|
||||
{
|
||||
struct {
|
||||
char* p0;
|
||||
int r;
|
||||
char __pad12[4];
|
||||
} __attribute__((__packed__, __gcc_struct__)) *a = v;
|
||||
a->r = puts((void*)a->p0);
|
||||
}
|
||||
|
||||
It extracts the arguments from the pointer to _Cfunc_puts's argument
|
||||
frame, invokes the system C function (in this case, puts), stores the
|
||||
result in the frame, and returns.
|
||||
|
||||
Linking
|
||||
|
||||
Once the _cgo_export.c and *.cgo2.c files have been compiled with gcc,
|
||||
they need to be linked into the final binary, along with the libraries
|
||||
they might depend on (in the case of puts, stdio). 6l has been
|
||||
extended to understand basic ELF files, but it does not understand ELF
|
||||
in the full complexity that modern C libraries embrace, so it cannot
|
||||
in general generate direct references to the system libraries.
|
||||
|
||||
Instead, the build process generates an object file using dynamic
|
||||
linkage to the desired libraries. The main function is provided by
|
||||
_cgo_main.c:
|
||||
|
||||
int main() { return 0; }
|
||||
void crosscall2(void(*fn)(void*, int), void *a, int c) { }
|
||||
void _cgo_allocate(void *a, int c) { }
|
||||
void _cgo_panic(void *a, int c) { }
|
||||
|
||||
The extra functions here are stubs to satisfy the references in the C
|
||||
code generated for gcc. The build process links this stub, along with
|
||||
_cgo_export.c and *.cgo2.c, into a dynamic executable and then lets
|
||||
cgo examine the executable. Cgo records the list of shared library
|
||||
references and resolved names and writes them into a new file
|
||||
_cgo_import.c, which looks like:
|
||||
|
||||
#pragma cgo_dynamic_linker "/lib64/ld-linux-x86-64.so.2"
|
||||
#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
|
||||
#pragma cgo_import_dynamic __libc_start_main __libc_start_main#GLIBC_2.2.5 "libc.so.6"
|
||||
#pragma cgo_import_dynamic stdout stdout#GLIBC_2.2.5 "libc.so.6"
|
||||
#pragma cgo_import_dynamic fflush fflush#GLIBC_2.2.5 "libc.so.6"
|
||||
#pragma cgo_import_dynamic _ _ "libpthread.so.0"
|
||||
#pragma cgo_import_dynamic _ _ "libc.so.6"
|
||||
|
||||
In the end, the compiled Go package, which will eventually be
|
||||
presented to 6l as part of a larger program, contains:
|
||||
|
||||
_go_.6 # 6g-compiled object for _cgo_gotypes.go *.cgo1.go
|
||||
_cgo_defun.6 # 6c-compiled object for _cgo_defun.c
|
||||
_all.o # gcc-compiled object for _cgo_export.c, *.cgo2.c
|
||||
_cgo_import.6 # 6c-compiled object for _cgo_import.c
|
||||
|
||||
The final program will be a dynamic executable, so that 6l can avoid
|
||||
needing to process arbitrary .o files. It only needs to process the .o
|
||||
files generated from C files that cgo writes, and those are much more
|
||||
limited in the ELF or other features that they use.
|
||||
|
||||
In essence, the _cgo_import.6 file includes the extra linking
|
||||
directives that 6l is not sophisticated enough to derive from _all.o
|
||||
on its own. Similarly, the _all.o uses dynamic references to real
|
||||
system object code because 6l is not sophisticated enough to process
|
||||
the real code.
|
||||
|
||||
The main benefits of this system are that 6l remains relatively simple
|
||||
(it does not need to implement a complete ELF and Mach-O linker) and
|
||||
that gcc is not needed after the package is compiled. For example,
|
||||
package net uses cgo for access to name resolution functions provided
|
||||
by libc. Although gcc is needed to compile package net, gcc is not
|
||||
needed to link programs that import package net.
|
||||
|
||||
Runtime
|
||||
|
||||
When using cgo, Go must not assume that it owns all details of the
|
||||
process. In particular it needs to coordinate with C in the use of
|
||||
threads and thread-local storage. The runtime package, in its own
|
||||
(6c-compiled) C code, declares a few uninitialized (default bss)
|
||||
variables:
|
||||
|
||||
bool runtime·iscgo;
|
||||
void (*libcgo_thread_start)(void*);
|
||||
void (*initcgo)(G*);
|
||||
|
||||
Any package using cgo imports "runtime/cgo", which provides
|
||||
initializations for these variables. It sets iscgo to 1, initcgo to a
|
||||
gcc-compiled function that can be called early during program startup,
|
||||
and libcgo_thread_start to a gcc-compiled function that can be used to
|
||||
create a new thread, in place of the runtime's usual direct system
|
||||
calls.
|
||||
|
||||
Internal and External Linking
|
||||
|
||||
The text above describes "internal" linking, in which 6l parses and
|
||||
links host object files (ELF, Mach-O, PE, and so on) into the final
|
||||
executable itself. Keeping 6l simple means we cannot possibly
|
||||
implement the full semantics of the host linker, so the kinds of
|
||||
objects that can be linked directly into the binary is limited (other
|
||||
code can only be used as a dynamic library). On the other hand, when
|
||||
using internal linking, 6l can generate Go binaries by itself.
|
||||
|
||||
In order to allow linking arbitrary object files without requiring
|
||||
dynamic libraries, cgo will soon support an "external" linking mode
|
||||
too. In external linking mode, 6l does not process any host object
|
||||
files. Instead, it collects all the Go code and writes a single go.o
|
||||
object file containing it. Then it invokes the host linker (usually
|
||||
gcc) to combine the go.o object file and any supporting non-Go code
|
||||
into a final executable. External linking avoids the dynamic library
|
||||
requirement but introduces a requirement that the host linker be
|
||||
present to create such a binary.
|
||||
|
||||
Most builds both compile source code and invoke the linker to create a
|
||||
binary. When cgo is involved, the compile step already requires gcc, so
|
||||
it is not problematic for the link step to require gcc too.
|
||||
|
||||
An important exception is builds using a pre-compiled copy of the
|
||||
standard library. In particular, package net uses cgo on most systems,
|
||||
and we want to preserve the ability to compile pure Go code that
|
||||
imports net without requiring gcc to be present at link time. (In this
|
||||
case, the dynamic library requirement is less significant, because the
|
||||
only library involved is libc.so, which can usually be assumed
|
||||
present.)
|
||||
|
||||
This conflict between functionality and the gcc requirement means we
|
||||
must support both internal and external linking, depending on the
|
||||
circumstances: if net is the only cgo-using package, then internal
|
||||
linking is probably fine, but if other packages are involved, so that there
|
||||
are dependencies on libraries beyond libc, external linking is likely
|
||||
to work better. The compilation of a package records the relevant
|
||||
information to support both linking modes, leaving the decision
|
||||
to be made when linking the final binary.
|
||||
|
||||
Linking Directives
|
||||
|
||||
In either linking mode, package-specific directives must be passed
|
||||
through to 6l. These are communicated by writing #pragma directives
|
||||
in a C source file compiled by 6c. The directives are copied into the .6 object file
|
||||
and then processed by the linker.
|
||||
|
||||
The directives are:
|
||||
|
||||
#pragma cgo_import_dynamic <local> [<remote> ["<library>"]]
|
||||
|
||||
In internal linking mode, allow an unresolved reference to
|
||||
<local>, assuming it will be resolved by a dynamic library
|
||||
symbol. The optional <remote> specifies the symbol's name and
|
||||
possibly version in the dynamic library, and the optional "<library>"
|
||||
names the specific library where the symbol should be found.
|
||||
|
||||
In the <remote>, # or @ can be used to introduce a symbol version.
|
||||
|
||||
Examples:
|
||||
#pragma cgo_import_dynamic puts
|
||||
#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5
|
||||
#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
|
||||
|
||||
A side effect of the cgo_import_dynamic directive with a
|
||||
library is to make the final binary depend on that dynamic
|
||||
library. To get the dependency without importing any specific
|
||||
symbols, use _ for local and remote.
|
||||
|
||||
Example:
|
||||
#pragma cgo_import_dynamic _ _ "libc.so.6"
|
||||
|
||||
For compatibility with current versions of SWIG,
|
||||
#pragma dynimport is an alias for #pragma cgo_import_dynamic.
|
||||
|
||||
#pragma cgo_dynamic_linker "<path>"
|
||||
|
||||
In internal linking mode, use "<path>" as the dynamic linker
|
||||
in the final binary. This directive is only needed from one
|
||||
package when constructing a binary; by convention it is
|
||||
supplied by runtime/cgo.
|
||||
|
||||
Example:
|
||||
#pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
|
||||
|
||||
#pragma cgo_export_dynamic <local> <remote>
|
||||
|
||||
In internal linking mode, put the Go symbol
|
||||
named <local> into the program's exported symbol table as
|
||||
<remote>, so that C code can refer to it by that name. This
|
||||
mechanism makes it possible for C code to call back into Go or
|
||||
to share Go's data.
|
||||
|
||||
For compatibility with current versions of SWIG,
|
||||
#pragma dynexport is an alias for #pragma cgo_export_dynamic.
|
||||
|
||||
#pragma cgo_import_static <local>
|
||||
|
||||
In external linking mode, allow unresolved references to
|
||||
<local> in the go.o object file prepared for the host linker,
|
||||
under the assumption that <local> will be supplied by the
|
||||
other object files that will be linked with go.o.
|
||||
|
||||
Example:
|
||||
#pragma cgo_import_static puts_wrapper
|
||||
|
||||
#pragma cgo_export_static <local> <remote>
|
||||
|
||||
In external linking mode, put the Go symbol
|
||||
named <local> into the program's exported symbol table as
|
||||
<remote>, so that C code can refer to it by that name. This
|
||||
mechanism makes it possible for C code to call back into Go or
|
||||
to share Go's data.
|
||||
|
||||
#pragma cgo_ldflag "<arg>"
|
||||
|
||||
In external linking mode, invoke the host linker (usually gcc)
|
||||
with "<arg>" as a command-line argument following the .o files.
|
||||
Note that the arguments are for "gcc", not "ld".
|
||||
|
||||
Example:
|
||||
#pragma cgo_ldflag "-lpthread"
|
||||
#pragma cgo_ldflag "-L/usr/local/sqlite3/lib"
|
||||
|
||||
A package compiled with cgo will include directives for both
|
||||
internal and external linking; the linker will select the appropriate
|
||||
subset for the chosen linking mode.
|
||||
|
||||
Example
|
||||
|
||||
As a simple example, consider a package that uses cgo to call C.sin.
|
||||
The following code will be generated by cgo:
|
||||
|
||||
// compiled by 6g
|
||||
|
||||
type _Ctype_double float64
|
||||
func _Cfunc_sin(_Ctype_double) _Ctype_double
|
||||
|
||||
// compiled by 6c
|
||||
|
||||
#pragma cgo_import_dynamic sin sin#GLIBC_2.2.5 "libm.so.6"
|
||||
|
||||
#pragma cgo_import_static _cgo_gcc_Cfunc_sin
|
||||
#pragma cgo_ldflag "-lm"
|
||||
|
||||
void _cgo_gcc_Cfunc_sin(void*);
|
||||
|
||||
void
|
||||
·_Cfunc_sin(struct{uint8 x[16];}p)
|
||||
{
|
||||
runtime·cgocall(_cgo_gcc_Cfunc_sin, &p);
|
||||
}
|
||||
|
||||
// compiled by gcc, into foo.cgo2.o
|
||||
|
||||
void
|
||||
_cgo_gcc_Cfunc_sin(void *v)
|
||||
{
|
||||
struct {
|
||||
double p0;
|
||||
double r;
|
||||
} __attribute__((__packed__)) *a = v;
|
||||
a->r = sin(a->p0);
|
||||
}
|
||||
|
||||
What happens at link time depends on whether the final binary is linked
|
||||
using the internal or external mode. If other packages are compiled in
|
||||
"external only" mode, then the final link will be an external one.
|
||||
Otherwise the link will be an internal one.
|
||||
|
||||
The directives in the 6c-compiled file are used according to the kind
|
||||
of final link used.
|
||||
|
||||
In internal mode, 6l itself processes all the host object files, in
|
||||
particular foo.cgo2.o. To do so, it uses the cgo_import_dynamic and
|
||||
cgo_dynamic_linker directives to learn that the otherwise undefined
|
||||
reference to sin in foo.cgo2.o should be rewritten to refer to the
|
||||
symbol sin with version GLIBC_2.2.5 from the dynamic library
|
||||
"libm.so.6", and the binary should request "/lib/ld-linux.so.2" as its
|
||||
runtime dynamic linker.
|
||||
|
||||
In external mode, 6l does not process any host object files, in
|
||||
particular foo.cgo2.o. It links together the 6g- and 6c-generated
|
||||
object files, along with any other Go code, into a go.o file. While
|
||||
doing that, 6l will discover that there is no definition for
|
||||
_cgo_gcc_Cfunc_sin, referred to by the 6c-compiled source file. This
|
||||
is okay, because 6l also processes the cgo_import_static directive and
|
||||
knows that _cgo_gcc_Cfunc_sin is expected to be supplied by a host
|
||||
object file, so 6l does not treat the missing symbol as an error when
|
||||
creating go.o. Indeed, the definition for _cgo_gcc_Cfunc_sin will be
|
||||
provided to the host linker by foo2.cgo.o, which in turn will need the
|
||||
symbol 'sin'. 6l also processes the cgo_ldflag directives, so that it
|
||||
knows that the eventual host link command must include the -lm
|
||||
argument, so that the host linker will be able to find 'sin' in the
|
||||
math library.
|
||||
|
||||
6l Command Line Interface
|
||||
|
||||
The go command and any other Go-aware build systems invoke 6l
|
||||
to link a collection of packages into a single binary. By default, 6l will
|
||||
present the same interface it does today:
|
||||
|
||||
6l main.a
|
||||
|
||||
produces a file named 6.out, even if 6l does so by invoking the host
|
||||
linker in external linking mode.
|
||||
|
||||
By default, 6l will decide the linking mode as follows: if the only
|
||||
packages using cgo are those on a whitelist of standard library
|
||||
packages (net, os/user, runtime/cgo), 6l will use internal linking
|
||||
mode. Otherwise, there are non-standard cgo packages involved, and 6l
|
||||
will use external linking mode. The first rule means that a build of
|
||||
the godoc binary, which uses net but no other cgo, can run without
|
||||
needing gcc available. The second rule means that a build of a
|
||||
cgo-wrapped library like sqlite3 can generate a standalone executable
|
||||
instead of needing to refer to a dynamic library. The specific choice
|
||||
can be overridden using a command line flag: 6l -linkmode=internal or
|
||||
6l -linkmode=external.
|
||||
|
||||
In an external link, 6l will create a temporary directory, write any
|
||||
host object files found in package archives to that directory (renamed
|
||||
to avoid conflicts), write the go.o file to that directory, and invoke
|
||||
the host linker. The default value for the host linker is $CC, split
|
||||
into fields, or else "gcc". The specific host linker command line can
|
||||
be overridden using command line flags: 6l -extld=clang
|
||||
-extldflags='-ggdb -O3'. If any package in a build includes a .cc or
|
||||
other file compiled by the C++ compiler, the go tool will use the
|
||||
-extld option to set the host linker to the C++ compiler.
|
||||
|
||||
These defaults mean that Go-aware build systems can ignore the linking
|
||||
changes and keep running plain '6l' and get reasonable results, but
|
||||
they can also control the linking details if desired.
|
||||
|
||||
*/
|
1728
libgo/go/cmd/cgo/gcc.go
Normal file
1728
libgo/go/cmd/cgo/gcc.go
Normal file
File diff suppressed because it is too large
Load Diff
294
libgo/go/cmd/cgo/godefs.go
Normal file
294
libgo/go/cmd/cgo/godefs.go
Normal file
@ -0,0 +1,294 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// godefs returns the output for -godefs mode.
|
||||
func (p *Package) godefs(f *File, srcfile string) string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n")
|
||||
fmt.Fprintf(&buf, "// %s\n", strings.Join(os.Args, " "))
|
||||
fmt.Fprintf(&buf, "\n")
|
||||
|
||||
override := make(map[string]string)
|
||||
|
||||
// Allow source file to specify override mappings.
|
||||
// For example, the socket data structures refer
|
||||
// to in_addr and in_addr6 structs but we want to be
|
||||
// able to treat them as byte arrays, so the godefs
|
||||
// inputs in package syscall say
|
||||
//
|
||||
// // +godefs map struct_in_addr [4]byte
|
||||
// // +godefs map struct_in_addr6 [16]byte
|
||||
//
|
||||
for _, g := range f.Comments {
|
||||
for _, c := range g.List {
|
||||
i := strings.Index(c.Text, "+godefs map")
|
||||
if i < 0 {
|
||||
continue
|
||||
}
|
||||
s := strings.TrimSpace(c.Text[i+len("+godefs map"):])
|
||||
i = strings.Index(s, " ")
|
||||
if i < 0 {
|
||||
fmt.Fprintf(os.Stderr, "invalid +godefs map comment: %s\n", c.Text)
|
||||
continue
|
||||
}
|
||||
override["_Ctype_"+strings.TrimSpace(s[:i])] = strings.TrimSpace(s[i:])
|
||||
}
|
||||
}
|
||||
for _, n := range f.Name {
|
||||
if s := override[n.Go]; s != "" {
|
||||
override[n.Mangle] = s
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, if the source file says type T C.whatever,
|
||||
// use "T" as the mangling of C.whatever,
|
||||
// except in the definition (handled at end of function).
|
||||
refName := make(map[*ast.Expr]*Name)
|
||||
for _, r := range f.Ref {
|
||||
refName[r.Expr] = r.Name
|
||||
}
|
||||
for _, d := range f.AST.Decls {
|
||||
d, ok := d.(*ast.GenDecl)
|
||||
if !ok || d.Tok != token.TYPE {
|
||||
continue
|
||||
}
|
||||
for _, s := range d.Specs {
|
||||
s := s.(*ast.TypeSpec)
|
||||
n := refName[&s.Type]
|
||||
if n != nil && n.Mangle != "" {
|
||||
override[n.Mangle] = s.Name.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extend overrides using typedefs:
|
||||
// If we know that C.xxx should format as T
|
||||
// and xxx is a typedef for yyy, make C.yyy format as T.
|
||||
for typ, def := range typedef {
|
||||
if new := override[typ]; new != "" {
|
||||
if id, ok := def.Go.(*ast.Ident); ok {
|
||||
override[id.Name] = new
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply overrides.
|
||||
for old, new := range override {
|
||||
if id := goIdent[old]; id != nil {
|
||||
id.Name = new
|
||||
}
|
||||
}
|
||||
|
||||
// Any names still using the _C syntax are not going to compile,
|
||||
// although in general we don't know whether they all made it
|
||||
// into the file, so we can't warn here.
|
||||
//
|
||||
// The most common case is union types, which begin with
|
||||
// _Ctype_union and for which typedef[name] is a Go byte
|
||||
// array of the appropriate size (such as [4]byte).
|
||||
// Substitute those union types with byte arrays.
|
||||
for name, id := range goIdent {
|
||||
if id.Name == name && strings.Contains(name, "_Ctype_union") {
|
||||
if def := typedef[name]; def != nil {
|
||||
id.Name = gofmt(def)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conf.Fprint(&buf, fset, f.AST)
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// cdefs returns the output for -cdefs mode.
|
||||
// The easiest way to do this is to translate the godefs Go to C.
|
||||
func (p *Package) cdefs(f *File, srcfile string) string {
|
||||
godefsOutput := p.godefs(f, srcfile)
|
||||
|
||||
lines := strings.Split(godefsOutput, "\n")
|
||||
lines[0] = "// Created by cgo -cdefs - DO NOT EDIT"
|
||||
|
||||
for i, line := range lines {
|
||||
lines[i] = strings.TrimSpace(line)
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) }
|
||||
|
||||
didTypedef := false
|
||||
for i := 0; i < len(lines); i++ {
|
||||
line := lines[i]
|
||||
|
||||
// Delete
|
||||
// package x
|
||||
if strings.HasPrefix(line, "package ") {
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert
|
||||
// const (
|
||||
// A = 1
|
||||
// B = 2
|
||||
// )
|
||||
//
|
||||
// to
|
||||
//
|
||||
// enum {
|
||||
// A = 1,
|
||||
// B = 2,
|
||||
// };
|
||||
if line == "const (" {
|
||||
printf("enum {\n")
|
||||
for i++; i < len(lines) && lines[i] != ")"; i++ {
|
||||
line = lines[i]
|
||||
if line != "" {
|
||||
printf("\t%s,", line)
|
||||
}
|
||||
printf("\n")
|
||||
}
|
||||
printf("};\n")
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert
|
||||
// const A = 1
|
||||
// to
|
||||
// enum { A = 1 };
|
||||
if strings.HasPrefix(line, "const ") {
|
||||
printf("enum { %s };\n", line[len("const "):])
|
||||
continue
|
||||
}
|
||||
|
||||
// On first type definition, typedef all the structs
|
||||
// in case there are dependencies between them.
|
||||
if !didTypedef && strings.HasPrefix(line, "type ") {
|
||||
didTypedef = true
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
|
||||
s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {")
|
||||
printf("typedef struct %s %s;\n", s, s)
|
||||
}
|
||||
}
|
||||
printf("\n")
|
||||
printf("#pragma pack on\n")
|
||||
printf("\n")
|
||||
}
|
||||
|
||||
// Convert
|
||||
// type T struct {
|
||||
// X int64
|
||||
// Y *int32
|
||||
// Z [4]byte
|
||||
// }
|
||||
//
|
||||
// to
|
||||
//
|
||||
// struct T {
|
||||
// int64 X;
|
||||
// int32 *Y;
|
||||
// byte Z[4];
|
||||
// }
|
||||
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
|
||||
if len(lines) > i+1 && lines[i+1] == "}" {
|
||||
// do not output empty struct
|
||||
i++
|
||||
continue
|
||||
}
|
||||
s := line[len("type ") : len(line)-len(" struct {")]
|
||||
printf("struct %s {\n", s)
|
||||
for i++; i < len(lines) && lines[i] != "}"; i++ {
|
||||
line := lines[i]
|
||||
if line != "" {
|
||||
f := strings.Fields(line)
|
||||
if len(f) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line)
|
||||
nerrors++
|
||||
continue
|
||||
}
|
||||
printf("\t%s;", cdecl(f[0], f[1]))
|
||||
}
|
||||
printf("\n")
|
||||
}
|
||||
printf("};\n")
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert
|
||||
// type T int
|
||||
// to
|
||||
// typedef int T;
|
||||
if strings.HasPrefix(line, "type ") {
|
||||
f := strings.Fields(line[len("type "):])
|
||||
if len(f) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line)
|
||||
nerrors++
|
||||
continue
|
||||
}
|
||||
printf("typedef\t%s;\n", cdecl(f[0], f[1]))
|
||||
continue
|
||||
}
|
||||
|
||||
printf("%s\n", line)
|
||||
}
|
||||
|
||||
if didTypedef {
|
||||
printf("\n")
|
||||
printf("#pragma pack off\n")
|
||||
}
|
||||
|
||||
return out.String()
|
||||
}
|
||||
|
||||
// cdecl returns the C declaration for the given Go name and type.
|
||||
// It only handles the specific cases necessary for converting godefs output.
|
||||
func cdecl(name, typ string) string {
|
||||
// X *[0]byte -> X *void
|
||||
if strings.HasPrefix(typ, "*[0]") {
|
||||
typ = "*void"
|
||||
}
|
||||
// X [4]byte -> X[4] byte
|
||||
for strings.HasPrefix(typ, "[") {
|
||||
i := strings.Index(typ, "]") + 1
|
||||
name = name + typ[:i]
|
||||
typ = typ[i:]
|
||||
}
|
||||
// X *byte -> *X byte
|
||||
for strings.HasPrefix(typ, "*") {
|
||||
name = "*" + name
|
||||
typ = typ[1:]
|
||||
}
|
||||
// X T -> T X
|
||||
// Handle the special case: 'unsafe.Pointer' is 'void *'
|
||||
if typ == "unsafe.Pointer" {
|
||||
typ = "void"
|
||||
name = "*" + name
|
||||
}
|
||||
return typ + "\t" + name
|
||||
}
|
||||
|
||||
var gofmtBuf bytes.Buffer
|
||||
|
||||
// gofmt returns the gofmt-formatted string for an AST node.
|
||||
func gofmt(n interface{}) string {
|
||||
gofmtBuf.Reset()
|
||||
err := printer.Fprint(&gofmtBuf, fset, n)
|
||||
if err != nil {
|
||||
return "<" + err.Error() + ">"
|
||||
}
|
||||
return gofmtBuf.String()
|
||||
}
|
360
libgo/go/cmd/cgo/main.go
Normal file
360
libgo/go/cmd/cgo/main.go
Normal file
@ -0,0 +1,360 @@
|
||||
// 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.
|
||||
|
||||
// Cgo; see gmp.go for an overview.
|
||||
|
||||
// TODO(rsc):
|
||||
// Emit correct line number annotations.
|
||||
// Make 6g understand the annotations.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A Package collects information about the package we're going to write.
|
||||
type Package struct {
|
||||
PackageName string // name of package
|
||||
PackagePath string
|
||||
PtrSize int64
|
||||
IntSize int64
|
||||
GccOptions []string
|
||||
CgoFlags map[string][]string // #cgo flags (CFLAGS, LDFLAGS)
|
||||
Written map[string]bool
|
||||
Name map[string]*Name // accumulated Name from Files
|
||||
ExpFunc []*ExpFunc // accumulated ExpFunc from Files
|
||||
Decl []ast.Decl
|
||||
GoFiles []string // list of Go files
|
||||
GccFiles []string // list of gcc output files
|
||||
Preamble string // collected preamble for _cgo_export.h
|
||||
}
|
||||
|
||||
// A File collects information about a single Go input file.
|
||||
type File struct {
|
||||
AST *ast.File // parsed AST
|
||||
Comments []*ast.CommentGroup // comments from file
|
||||
Package string // Package name
|
||||
Preamble string // C preamble (doc comment on import "C")
|
||||
Ref []*Ref // all references to C.xxx in AST
|
||||
ExpFunc []*ExpFunc // exported functions for this file
|
||||
Name map[string]*Name // map from Go name to Name
|
||||
}
|
||||
|
||||
func nameKeys(m map[string]*Name) []string {
|
||||
var ks []string
|
||||
for k := range m {
|
||||
ks = append(ks, k)
|
||||
}
|
||||
sort.Strings(ks)
|
||||
return ks
|
||||
}
|
||||
|
||||
// A Ref refers to an expression of the form C.xxx in the AST.
|
||||
type Ref struct {
|
||||
Name *Name
|
||||
Expr *ast.Expr
|
||||
Context string // "type", "expr", "call", or "call2"
|
||||
}
|
||||
|
||||
func (r *Ref) Pos() token.Pos {
|
||||
return (*r.Expr).Pos()
|
||||
}
|
||||
|
||||
// A Name collects information about C.xxx.
|
||||
type Name struct {
|
||||
Go string // name used in Go referring to package C
|
||||
Mangle string // name used in generated Go
|
||||
C string // name used in C
|
||||
Define string // #define expansion
|
||||
Kind string // "const", "type", "var", "fpvar", "func", "not-type"
|
||||
Type *Type // the type of xxx
|
||||
FuncType *FuncType
|
||||
AddError bool
|
||||
Const string // constant definition
|
||||
}
|
||||
|
||||
// IsVar returns true if Kind is either "var" or "fpvar"
|
||||
func (n *Name) IsVar() bool {
|
||||
return n.Kind == "var" || n.Kind == "fpvar"
|
||||
}
|
||||
|
||||
// A ExpFunc is an exported function, callable from C.
|
||||
// Such functions are identified in the Go input file
|
||||
// by doc comments containing the line //export ExpName
|
||||
type ExpFunc struct {
|
||||
Func *ast.FuncDecl
|
||||
ExpName string // name to use from C
|
||||
}
|
||||
|
||||
// A TypeRepr contains the string representation of a type.
|
||||
type TypeRepr struct {
|
||||
Repr string
|
||||
FormatArgs []interface{}
|
||||
}
|
||||
|
||||
// A Type collects information about a type in both the C and Go worlds.
|
||||
type Type struct {
|
||||
Size int64
|
||||
Align int64
|
||||
C *TypeRepr
|
||||
Go ast.Expr
|
||||
EnumValues map[string]int64
|
||||
Typedef string
|
||||
}
|
||||
|
||||
// A FuncType collects information about a function type in both the C and Go worlds.
|
||||
type FuncType struct {
|
||||
Params []*Type
|
||||
Result *Type
|
||||
Go *ast.FuncType
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
var ptrSizeMap = map[string]int64{
|
||||
"386": 4,
|
||||
"amd64": 8,
|
||||
"arm": 4,
|
||||
"ppc64": 8,
|
||||
"ppc64le": 8,
|
||||
"s390x": 8,
|
||||
}
|
||||
|
||||
var intSizeMap = map[string]int64{
|
||||
"386": 4,
|
||||
"amd64": 8,
|
||||
"arm": 4,
|
||||
"ppc64": 8,
|
||||
"ppc64le": 8,
|
||||
"s390x": 8,
|
||||
}
|
||||
|
||||
var cPrefix string
|
||||
|
||||
var fset = token.NewFileSet()
|
||||
|
||||
var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
|
||||
var dynout = flag.String("dynout", "", "write -dynobj output to this file")
|
||||
var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in dynimport mode")
|
||||
|
||||
// These flags are for bootstrapping a new Go implementation,
|
||||
// to generate Go and C headers that match the data layout and
|
||||
// constant values used in the host's C libraries and system calls.
|
||||
var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
|
||||
var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output")
|
||||
var objDir = flag.String("objdir", "", "object directory")
|
||||
|
||||
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
|
||||
var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
|
||||
var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
|
||||
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
|
||||
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
|
||||
var goarch, goos string
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
|
||||
if *dynobj != "" {
|
||||
// cgo -dynimport is essentially a separate helper command
|
||||
// built into the cgo binary. It scans a gcc-produced executable
|
||||
// and dumps information about the imported symbols and the
|
||||
// imported libraries. The 'go build' rules for cgo prepare an
|
||||
// appropriate executable and then use its import information
|
||||
// instead of needing to make the linkers duplicate all the
|
||||
// specialized knowledge gcc has about where to look for imported
|
||||
// symbols and which ones to use.
|
||||
dynimport(*dynobj)
|
||||
return
|
||||
}
|
||||
|
||||
if *godefs && *cdefs {
|
||||
fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
if *godefs || *cdefs {
|
||||
// Generating definitions pulled from header files,
|
||||
// to be checked into Go repositories.
|
||||
// Line numbers are just noise.
|
||||
conf.Mode &^= printer.SourcePos
|
||||
}
|
||||
|
||||
args := flag.Args()
|
||||
if len(args) < 1 {
|
||||
usage()
|
||||
}
|
||||
|
||||
// Find first arg that looks like a go file and assume everything before
|
||||
// that are options to pass to gcc.
|
||||
var i int
|
||||
for i = len(args); i > 0; i-- {
|
||||
if !strings.HasSuffix(args[i-1], ".go") {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(args) {
|
||||
usage()
|
||||
}
|
||||
|
||||
goFiles := args[i:]
|
||||
|
||||
p := newPackage(args[:i])
|
||||
|
||||
// Record CGO_LDFLAGS from the environment for external linking.
|
||||
if ldflags := os.Getenv("CGO_LDFLAGS"); ldflags != "" {
|
||||
args, err := splitQuoted(ldflags)
|
||||
if err != nil {
|
||||
fatalf("bad CGO_LDFLAGS: %q (%s)", ldflags, err)
|
||||
}
|
||||
p.addToFlag("LDFLAGS", args)
|
||||
}
|
||||
|
||||
// Need a unique prefix for the global C symbols that
|
||||
// we use to coordinate between gcc and ourselves.
|
||||
// We already put _cgo_ at the beginning, so the main
|
||||
// concern is other cgo wrappers for the same functions.
|
||||
// Use the beginning of the md5 of the input to disambiguate.
|
||||
h := md5.New()
|
||||
for _, input := range goFiles {
|
||||
f, err := os.Open(input)
|
||||
if err != nil {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
io.Copy(h, f)
|
||||
f.Close()
|
||||
}
|
||||
cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
|
||||
|
||||
fs := make([]*File, len(goFiles))
|
||||
for i, input := range goFiles {
|
||||
f := new(File)
|
||||
f.ReadGo(input)
|
||||
f.DiscardCgoDirectives()
|
||||
fs[i] = f
|
||||
}
|
||||
|
||||
if *objDir == "" {
|
||||
// make sure that _obj directory exists, so that we can write
|
||||
// all the output files there.
|
||||
os.Mkdir("_obj", 0777)
|
||||
*objDir = "_obj"
|
||||
}
|
||||
*objDir += string(filepath.Separator)
|
||||
|
||||
for i, input := range goFiles {
|
||||
f := fs[i]
|
||||
p.Translate(f)
|
||||
for _, cref := range f.Ref {
|
||||
switch cref.Context {
|
||||
case "call", "call2":
|
||||
if cref.Name.Kind != "type" {
|
||||
break
|
||||
}
|
||||
*cref.Expr = cref.Name.Type.Go
|
||||
}
|
||||
}
|
||||
if nerrors > 0 {
|
||||
os.Exit(2)
|
||||
}
|
||||
pkg := f.Package
|
||||
if dir := os.Getenv("CGOPKGPATH"); dir != "" {
|
||||
pkg = filepath.Join(dir, pkg)
|
||||
}
|
||||
p.PackagePath = pkg
|
||||
p.Record(f)
|
||||
if *godefs {
|
||||
os.Stdout.WriteString(p.godefs(f, input))
|
||||
} else if *cdefs {
|
||||
os.Stdout.WriteString(p.cdefs(f, input))
|
||||
} else {
|
||||
p.writeOutput(f, input)
|
||||
}
|
||||
}
|
||||
|
||||
if !*godefs && !*cdefs {
|
||||
p.writeDefs()
|
||||
}
|
||||
if nerrors > 0 {
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
// newPackage returns a new Package that will invoke
|
||||
// gcc with the additional arguments specified in args.
|
||||
func newPackage(args []string) *Package {
|
||||
goarch = runtime.GOARCH
|
||||
if s := os.Getenv("GOARCH"); s != "" {
|
||||
goarch = s
|
||||
}
|
||||
goos = runtime.GOOS
|
||||
if s := os.Getenv("GOOS"); s != "" {
|
||||
goos = s
|
||||
}
|
||||
ptrSize := ptrSizeMap[goarch]
|
||||
if ptrSize == 0 {
|
||||
fatalf("unknown ptrSize for $GOARCH %q", goarch)
|
||||
}
|
||||
intSize := intSizeMap[goarch]
|
||||
if intSize == 0 {
|
||||
fatalf("unknown intSize for $GOARCH %q", goarch)
|
||||
}
|
||||
|
||||
// Reset locale variables so gcc emits English errors [sic].
|
||||
os.Setenv("LANG", "en_US.UTF-8")
|
||||
os.Setenv("LC_ALL", "C")
|
||||
|
||||
p := &Package{
|
||||
PtrSize: ptrSize,
|
||||
IntSize: intSize,
|
||||
CgoFlags: make(map[string][]string),
|
||||
Written: make(map[string]bool),
|
||||
}
|
||||
p.addToFlag("CFLAGS", args)
|
||||
return p
|
||||
}
|
||||
|
||||
// Record what needs to be recorded about f.
|
||||
func (p *Package) Record(f *File) {
|
||||
if p.PackageName == "" {
|
||||
p.PackageName = f.Package
|
||||
} else if p.PackageName != f.Package {
|
||||
error_(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
|
||||
}
|
||||
|
||||
if p.Name == nil {
|
||||
p.Name = f.Name
|
||||
} else {
|
||||
for k, v := range f.Name {
|
||||
if p.Name[k] == nil {
|
||||
p.Name[k] = v
|
||||
} else if !reflect.DeepEqual(p.Name[k], v) {
|
||||
error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if f.ExpFunc != nil {
|
||||
p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
|
||||
p.Preamble += "\n" + f.Preamble
|
||||
}
|
||||
p.Decl = append(p.Decl, f.AST.Decls...)
|
||||
}
|
1299
libgo/go/cmd/cgo/out.go
Normal file
1299
libgo/go/cmd/cgo/out.go
Normal file
File diff suppressed because it is too large
Load Diff
84
libgo/go/cmd/cgo/util.go
Normal file
84
libgo/go/cmd/cgo/util.go
Normal file
@ -0,0 +1,84 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// run runs the command argv, feeding in stdin on standard input.
|
||||
// It returns the output to standard output and standard error.
|
||||
// ok indicates whether the command exited successfully.
|
||||
func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
|
||||
p := exec.Command(argv[0], argv[1:]...)
|
||||
p.Stdin = bytes.NewReader(stdin)
|
||||
var bout, berr bytes.Buffer
|
||||
p.Stdout = &bout
|
||||
p.Stderr = &berr
|
||||
err := p.Run()
|
||||
if _, ok := err.(*exec.ExitError); err != nil && !ok {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
ok = p.ProcessState.Success()
|
||||
stdout, stderr = bout.Bytes(), berr.Bytes()
|
||||
return
|
||||
}
|
||||
|
||||
func lineno(pos token.Pos) string {
|
||||
return fset.Position(pos).String()
|
||||
}
|
||||
|
||||
// Die with an error message.
|
||||
func fatalf(msg string, args ...interface{}) {
|
||||
// If we've already printed other errors, they might have
|
||||
// caused the fatal condition. Assume they're enough.
|
||||
if nerrors == 0 {
|
||||
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
||||
}
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
var nerrors int
|
||||
|
||||
func error_(pos token.Pos, msg string, args ...interface{}) {
|
||||
nerrors++
|
||||
if pos.IsValid() {
|
||||
fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, msg, args...)
|
||||
fmt.Fprintf(os.Stderr, "\n")
|
||||
}
|
||||
|
||||
// isName returns true if s is a valid C identifier
|
||||
func isName(s string) bool {
|
||||
for i, v := range s {
|
||||
if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') {
|
||||
return false
|
||||
}
|
||||
if i == 0 && '0' <= v && v <= '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return s != ""
|
||||
}
|
||||
|
||||
func creat(name string) *os.File {
|
||||
f, err := os.Create(name)
|
||||
if err != nil {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func slashToUnderscore(c rune) rune {
|
||||
if c == '/' || c == '\\' || c == ':' {
|
||||
c = '_'
|
||||
}
|
||||
return c
|
||||
}
|
30
libgo/go/cmd/go/bootstrap.go
Normal file
30
libgo/go/cmd/go/bootstrap.go
Normal file
@ -0,0 +1,30 @@
|
||||
// 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 cmd_go_bootstrap
|
||||
|
||||
// This code is compiled only into the bootstrap 'go' binary.
|
||||
// These stubs avoid importing packages with large dependency
|
||||
// trees, like the use of "net/http" in vcs.go.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
var errHTTP = errors.New("no http in bootstrap go command")
|
||||
|
||||
func httpGET(url string) ([]byte, error) {
|
||||
return nil, errHTTP
|
||||
}
|
||||
|
||||
func httpsOrHTTP(importPath string) (string, io.ReadCloser, error) {
|
||||
return "", nil, errHTTP
|
||||
}
|
||||
|
||||
func parseMetaGoImports(r io.Reader) ([]metaImport, error) {
|
||||
panic("unreachable")
|
||||
}
|
2594
libgo/go/cmd/go/build.go
Normal file
2594
libgo/go/cmd/go/build.go
Normal file
File diff suppressed because it is too large
Load Diff
248
libgo/go/cmd/go/clean.go
Normal file
248
libgo/go/cmd/go/clean.go
Normal file
@ -0,0 +1,248 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var cmdClean = &Command{
|
||||
UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]",
|
||||
Short: "remove object files",
|
||||
Long: `
|
||||
Clean removes object files from package source directories.
|
||||
The go command builds most objects in a temporary directory,
|
||||
so go clean is mainly concerned with object files left by other
|
||||
tools or by manual invocations of go build.
|
||||
|
||||
Specifically, clean removes the following files from each of the
|
||||
source directories corresponding to the import paths:
|
||||
|
||||
_obj/ old object directory, left from Makefiles
|
||||
_test/ old test directory, left from Makefiles
|
||||
_testmain.go old gotest file, left from Makefiles
|
||||
test.out old test log, left from Makefiles
|
||||
build.out old test log, left from Makefiles
|
||||
*.[568ao] object files, left from Makefiles
|
||||
|
||||
DIR(.exe) from go build
|
||||
DIR.test(.exe) from go test -c
|
||||
MAINFILE(.exe) from go build MAINFILE.go
|
||||
*.so from SWIG
|
||||
|
||||
In the list, DIR represents the final path element of the
|
||||
directory, and MAINFILE is the base name of any Go source
|
||||
file in the directory that is not included when building
|
||||
the package.
|
||||
|
||||
The -i flag causes clean to remove the corresponding installed
|
||||
archive or binary (what 'go install' would create).
|
||||
|
||||
The -n flag causes clean to print the remove commands it would execute,
|
||||
but not run them.
|
||||
|
||||
The -r flag causes clean to be applied recursively to all the
|
||||
dependencies of the packages named by the import paths.
|
||||
|
||||
The -x flag causes clean to print remove commands as it executes them.
|
||||
|
||||
For more about build flags, see 'go help build'.
|
||||
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
`,
|
||||
}
|
||||
|
||||
var cleanI bool // clean -i flag
|
||||
var cleanR bool // clean -r flag
|
||||
|
||||
func init() {
|
||||
// break init cycle
|
||||
cmdClean.Run = runClean
|
||||
|
||||
cmdClean.Flag.BoolVar(&cleanI, "i", false, "")
|
||||
cmdClean.Flag.BoolVar(&cleanR, "r", false, "")
|
||||
// -n and -x are important enough to be
|
||||
// mentioned explicitly in the docs but they
|
||||
// are part of the build flags.
|
||||
|
||||
addBuildFlags(cmdClean)
|
||||
}
|
||||
|
||||
func runClean(cmd *Command, args []string) {
|
||||
for _, pkg := range packagesAndErrors(args) {
|
||||
clean(pkg)
|
||||
}
|
||||
}
|
||||
|
||||
var cleaned = map[*Package]bool{}
|
||||
|
||||
// TODO: These are dregs left by Makefile-based builds.
|
||||
// Eventually, can stop deleting these.
|
||||
var cleanDir = map[string]bool{
|
||||
"_test": true,
|
||||
"_obj": true,
|
||||
}
|
||||
|
||||
var cleanFile = map[string]bool{
|
||||
"_testmain.go": true,
|
||||
"test.out": true,
|
||||
"build.out": true,
|
||||
"a.out": true,
|
||||
}
|
||||
|
||||
var cleanExt = map[string]bool{
|
||||
".5": true,
|
||||
".6": true,
|
||||
".8": true,
|
||||
".a": true,
|
||||
".o": true,
|
||||
".so": true,
|
||||
}
|
||||
|
||||
func clean(p *Package) {
|
||||
if cleaned[p] {
|
||||
return
|
||||
}
|
||||
cleaned[p] = true
|
||||
|
||||
if p.Dir == "" {
|
||||
errorf("can't load package: %v", p.Error)
|
||||
return
|
||||
}
|
||||
dirs, err := ioutil.ReadDir(p.Dir)
|
||||
if err != nil {
|
||||
errorf("go clean %s: %v", p.Dir, err)
|
||||
return
|
||||
}
|
||||
|
||||
var b builder
|
||||
b.print = fmt.Print
|
||||
|
||||
packageFile := map[string]bool{}
|
||||
if p.Name != "main" {
|
||||
// Record which files are not in package main.
|
||||
// The others are.
|
||||
keep := func(list []string) {
|
||||
for _, f := range list {
|
||||
packageFile[f] = true
|
||||
}
|
||||
}
|
||||
keep(p.GoFiles)
|
||||
keep(p.CgoFiles)
|
||||
keep(p.TestGoFiles)
|
||||
keep(p.XTestGoFiles)
|
||||
}
|
||||
|
||||
_, elem := filepath.Split(p.Dir)
|
||||
var allRemove []string
|
||||
|
||||
// Remove dir-named executable only if this is package main.
|
||||
if p.Name == "main" {
|
||||
allRemove = append(allRemove,
|
||||
elem,
|
||||
elem+".exe",
|
||||
)
|
||||
}
|
||||
|
||||
// Remove package test executables.
|
||||
allRemove = append(allRemove,
|
||||
elem+".test",
|
||||
elem+".test.exe",
|
||||
)
|
||||
|
||||
// Remove a potential executable for each .go file in the directory that
|
||||
// is not part of the directory's package.
|
||||
for _, dir := range dirs {
|
||||
name := dir.Name()
|
||||
if packageFile[name] {
|
||||
continue
|
||||
}
|
||||
if !dir.IsDir() && strings.HasSuffix(name, ".go") {
|
||||
// TODO(adg,rsc): check that this .go file is actually
|
||||
// in "package main", and therefore capable of building
|
||||
// to an executable file.
|
||||
base := name[:len(name)-len(".go")]
|
||||
allRemove = append(allRemove, base, base+".exe")
|
||||
}
|
||||
}
|
||||
|
||||
if buildN || buildX {
|
||||
b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
|
||||
}
|
||||
|
||||
toRemove := map[string]bool{}
|
||||
for _, name := range allRemove {
|
||||
toRemove[name] = true
|
||||
}
|
||||
for _, dir := range dirs {
|
||||
name := dir.Name()
|
||||
if dir.IsDir() {
|
||||
// TODO: Remove once Makefiles are forgotten.
|
||||
if cleanDir[name] {
|
||||
if buildN || buildX {
|
||||
b.showcmd(p.Dir, "rm -r %s", name)
|
||||
if buildN {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
|
||||
errorf("go clean: %v", err)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if buildN {
|
||||
continue
|
||||
}
|
||||
|
||||
if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] {
|
||||
removeFile(filepath.Join(p.Dir, name))
|
||||
}
|
||||
}
|
||||
|
||||
if cleanI && p.target != "" {
|
||||
if buildN || buildX {
|
||||
b.showcmd("", "rm -f %s", p.target)
|
||||
}
|
||||
if !buildN {
|
||||
removeFile(p.target)
|
||||
}
|
||||
}
|
||||
|
||||
if cleanR {
|
||||
for _, p1 := range p.imports {
|
||||
clean(p1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// removeFile tries to remove file f, if error other than file doesn't exist
|
||||
// occurs, it will report the error.
|
||||
func removeFile(f string) {
|
||||
err := os.Remove(f)
|
||||
if err == nil || os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
// Windows does not allow deletion of a binary file while it is executing.
|
||||
if toolIsWindows {
|
||||
// Remove lingering ~ file from last attempt.
|
||||
if _, err2 := os.Stat(f + "~"); err2 == nil {
|
||||
os.Remove(f + "~")
|
||||
}
|
||||
// Try to move it out of the way. If the move fails,
|
||||
// which is likely, we'll try again the
|
||||
// next time we do an install of this binary.
|
||||
if err2 := os.Rename(f, f+"~"); err2 == nil {
|
||||
os.Remove(f + "~")
|
||||
return
|
||||
}
|
||||
}
|
||||
errorf("go clean: %v", err)
|
||||
}
|
36
libgo/go/cmd/go/context.go
Normal file
36
libgo/go/cmd/go/context.go
Normal file
@ -0,0 +1,36 @@
|
||||
// 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 (
|
||||
"go/build"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
GOARCH string `json:",omitempty"` // target architecture
|
||||
GOOS string `json:",omitempty"` // target operating system
|
||||
GOROOT string `json:",omitempty"` // Go root
|
||||
GOPATH string `json:",omitempty"` // Go path
|
||||
CgoEnabled bool `json:",omitempty"` // whether cgo can be used
|
||||
UseAllFiles bool `json:",omitempty"` // use files regardless of +build lines, file names
|
||||
Compiler string `json:",omitempty"` // compiler to assume when computing target paths
|
||||
BuildTags []string `json:",omitempty"` // build constraints to match in +build lines
|
||||
ReleaseTags []string `json:",omitempty"` // releases the current release is compatible with
|
||||
InstallSuffix string `json:",omitempty"` // suffix to use in the name of the install dir
|
||||
}
|
||||
|
||||
func newContext(c *build.Context) *Context {
|
||||
return &Context{
|
||||
GOARCH: c.GOARCH,
|
||||
GOOS: c.GOOS,
|
||||
GOROOT: c.GOROOT,
|
||||
CgoEnabled: c.CgoEnabled,
|
||||
UseAllFiles: c.UseAllFiles,
|
||||
Compiler: c.Compiler,
|
||||
BuildTags: c.BuildTags,
|
||||
ReleaseTags: c.ReleaseTags,
|
||||
InstallSuffix: c.InstallSuffix,
|
||||
}
|
||||
}
|
83
libgo/go/cmd/go/discovery.go
Normal file
83
libgo/go/cmd/go/discovery.go
Normal file
@ -0,0 +1,83 @@
|
||||
// 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 !cmd_go_bootstrap
|
||||
|
||||
// This code is compiled into the real 'go' binary, but it is not
|
||||
// compiled into the binary that is built during all.bash, so as
|
||||
// to avoid needing to build net (and thus use cgo) during the
|
||||
// bootstrap process.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// charsetReader returns a reader for the given charset. Currently
|
||||
// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
|
||||
// error which is printed by go get, so the user can find why the package
|
||||
// wasn't downloaded if the encoding is not supported. Note that, in
|
||||
// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
|
||||
// greater than 0x7f are not rejected).
|
||||
func charsetReader(charset string, input io.Reader) (io.Reader, error) {
|
||||
switch strings.ToLower(charset) {
|
||||
case "ascii":
|
||||
return input, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
|
||||
}
|
||||
}
|
||||
|
||||
// parseMetaGoImports returns meta imports from the HTML in r.
|
||||
// Parsing ends at the end of the <head> section or the beginning of the <body>.
|
||||
func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
|
||||
d := xml.NewDecoder(r)
|
||||
d.CharsetReader = charsetReader
|
||||
d.Strict = false
|
||||
var t xml.Token
|
||||
for {
|
||||
t, err = d.Token()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
|
||||
return
|
||||
}
|
||||
if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
|
||||
return
|
||||
}
|
||||
e, ok := t.(xml.StartElement)
|
||||
if !ok || !strings.EqualFold(e.Name.Local, "meta") {
|
||||
continue
|
||||
}
|
||||
if attrValue(e.Attr, "name") != "go-import" {
|
||||
continue
|
||||
}
|
||||
if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
|
||||
imports = append(imports, metaImport{
|
||||
Prefix: f[0],
|
||||
VCS: f[1],
|
||||
RepoRoot: f[2],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// attrValue returns the attribute value for the case-insensitive key
|
||||
// `name', or the empty string if nothing is found.
|
||||
func attrValue(attrs []xml.Attr, name string) string {
|
||||
for _, a := range attrs {
|
||||
if strings.EqualFold(a.Name.Local, name) {
|
||||
return a.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
990
libgo/go/cmd/go/doc.go
Normal file
990
libgo/go/cmd/go/doc.go
Normal file
@ -0,0 +1,990 @@
|
||||
// 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.
|
||||
|
||||
// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
|
||||
// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
|
||||
|
||||
/*
|
||||
Go is a tool for managing Go source code.
|
||||
|
||||
Usage:
|
||||
|
||||
go command [arguments]
|
||||
|
||||
The commands are:
|
||||
|
||||
build compile packages and dependencies
|
||||
clean remove object files
|
||||
env print Go environment information
|
||||
fix run go tool fix on packages
|
||||
fmt run gofmt on package sources
|
||||
get download and install packages and dependencies
|
||||
install compile and install packages and dependencies
|
||||
list list packages
|
||||
run compile and run Go program
|
||||
test test packages
|
||||
tool run specified go tool
|
||||
version print Go version
|
||||
vet run go tool vet on packages
|
||||
|
||||
Use "go help [command]" for more information about a command.
|
||||
|
||||
Additional help topics:
|
||||
|
||||
c calling between Go and C
|
||||
filetype file types
|
||||
gopath GOPATH environment variable
|
||||
importpath import path syntax
|
||||
packages description of package lists
|
||||
testflag description of testing flags
|
||||
testfunc description of testing functions
|
||||
|
||||
Use "go help [topic]" for more information about that topic.
|
||||
|
||||
|
||||
Compile packages and dependencies
|
||||
|
||||
Usage:
|
||||
|
||||
go build [-o output] [-i] [build flags] [packages]
|
||||
|
||||
Build compiles the packages named by the import paths,
|
||||
along with their dependencies, but it does not install the results.
|
||||
|
||||
If the arguments are a list of .go files, build treats them as a list
|
||||
of source files specifying a single package.
|
||||
|
||||
When the command line specifies a single main package,
|
||||
build writes the resulting executable to output.
|
||||
Otherwise build compiles the packages but discards the results,
|
||||
serving only as a check that the packages can be built.
|
||||
|
||||
The -o flag specifies the output file name. If not specified, the
|
||||
output file name depends on the arguments and derives from the name
|
||||
of the package, such as p.a for package p, unless p is 'main'. If
|
||||
the package is main and file names are provided, the file name
|
||||
derives from the first file name mentioned, such as f1 for 'go build
|
||||
f1.go f2.go'; with no files provided ('go build'), the output file
|
||||
name is the base name of the containing directory.
|
||||
|
||||
The -i flag installs the packages that are dependencies of the target.
|
||||
|
||||
The build flags are shared by the build, clean, get, install, list, run,
|
||||
and test commands:
|
||||
|
||||
-a
|
||||
force rebuilding of packages that are already up-to-date.
|
||||
-n
|
||||
print the commands but do not run them.
|
||||
-p n
|
||||
the number of builds that can be run in parallel.
|
||||
The default is the number of CPUs available.
|
||||
-race
|
||||
enable data race detection.
|
||||
Supported only on linux/amd64, darwin/amd64 and windows/amd64.
|
||||
-v
|
||||
print the names of packages as they are compiled.
|
||||
-work
|
||||
print the name of the temporary work directory and
|
||||
do not delete it when exiting.
|
||||
-x
|
||||
print the commands.
|
||||
|
||||
-ccflags 'arg list'
|
||||
arguments to pass on each 5c, 6c, or 8c compiler invocation.
|
||||
-compiler name
|
||||
name of compiler to use, as in runtime.Compiler (gccgo or gc).
|
||||
-gccgoflags 'arg list'
|
||||
arguments to pass on each gccgo compiler/linker invocation.
|
||||
-gcflags 'arg list'
|
||||
arguments to pass on each 5g, 6g, or 8g compiler invocation.
|
||||
-installsuffix suffix
|
||||
a suffix to use in the name of the package installation directory,
|
||||
in order to keep output separate from default builds.
|
||||
If using the -race flag, the install suffix is automatically set to race
|
||||
or, if set explicitly, has _race appended to it.
|
||||
-ldflags 'flag list'
|
||||
arguments to pass on each 5l, 6l, or 8l linker invocation.
|
||||
-tags 'tag list'
|
||||
a list of build tags to consider satisfied during the build.
|
||||
For more information about build tags, see the description of
|
||||
build constraints in the documentation for the go/build package.
|
||||
|
||||
The list flags accept a space-separated list of strings. To embed spaces
|
||||
in an element in the list, surround it with either single or double quotes.
|
||||
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
For more about where packages and binaries are installed,
|
||||
run 'go help gopath'. For more about calling between Go and C/C++,
|
||||
run 'go help c'.
|
||||
|
||||
See also: go install, go get, go clean.
|
||||
|
||||
|
||||
Remove object files
|
||||
|
||||
Usage:
|
||||
|
||||
go clean [-i] [-r] [-n] [-x] [build flags] [packages]
|
||||
|
||||
Clean removes object files from package source directories.
|
||||
The go command builds most objects in a temporary directory,
|
||||
so go clean is mainly concerned with object files left by other
|
||||
tools or by manual invocations of go build.
|
||||
|
||||
Specifically, clean removes the following files from each of the
|
||||
source directories corresponding to the import paths:
|
||||
|
||||
_obj/ old object directory, left from Makefiles
|
||||
_test/ old test directory, left from Makefiles
|
||||
_testmain.go old gotest file, left from Makefiles
|
||||
test.out old test log, left from Makefiles
|
||||
build.out old test log, left from Makefiles
|
||||
*.[568ao] object files, left from Makefiles
|
||||
|
||||
DIR(.exe) from go build
|
||||
DIR.test(.exe) from go test -c
|
||||
MAINFILE(.exe) from go build MAINFILE.go
|
||||
*.so from SWIG
|
||||
|
||||
In the list, DIR represents the final path element of the
|
||||
directory, and MAINFILE is the base name of any Go source
|
||||
file in the directory that is not included when building
|
||||
the package.
|
||||
|
||||
The -i flag causes clean to remove the corresponding installed
|
||||
archive or binary (what 'go install' would create).
|
||||
|
||||
The -n flag causes clean to print the remove commands it would execute,
|
||||
but not run them.
|
||||
|
||||
The -r flag causes clean to be applied recursively to all the
|
||||
dependencies of the packages named by the import paths.
|
||||
|
||||
The -x flag causes clean to print remove commands as it executes them.
|
||||
|
||||
For more about build flags, see 'go help build'.
|
||||
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
|
||||
Print Go environment information
|
||||
|
||||
Usage:
|
||||
|
||||
go env [var ...]
|
||||
|
||||
Env prints Go environment information.
|
||||
|
||||
By default env prints information as a shell script
|
||||
(on Windows, a batch file). If one or more variable
|
||||
names is given as arguments, env prints the value of
|
||||
each named variable on its own line.
|
||||
|
||||
|
||||
Run go tool fix on packages
|
||||
|
||||
Usage:
|
||||
|
||||
go fix [packages]
|
||||
|
||||
Fix runs the Go fix command on the packages named by the import paths.
|
||||
|
||||
For more about fix, see 'godoc fix'.
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
To run fix with specific options, run 'go tool fix'.
|
||||
|
||||
See also: go fmt, go vet.
|
||||
|
||||
|
||||
Run gofmt on package sources
|
||||
|
||||
Usage:
|
||||
|
||||
go fmt [-n] [-x] [packages]
|
||||
|
||||
Fmt runs the command 'gofmt -l -w' on the packages named
|
||||
by the import paths. It prints the names of the files that are modified.
|
||||
|
||||
For more about gofmt, see 'godoc gofmt'.
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
The -n flag prints commands that would be executed.
|
||||
The -x flag prints commands as they are executed.
|
||||
|
||||
To run gofmt with specific options, run gofmt itself.
|
||||
|
||||
See also: go fix, go vet.
|
||||
|
||||
|
||||
Download and install packages and dependencies
|
||||
|
||||
Usage:
|
||||
|
||||
go get [-d] [-fix] [-t] [-u] [build flags] [packages]
|
||||
|
||||
Get downloads and installs the packages named by the import paths,
|
||||
along with their dependencies.
|
||||
|
||||
The -d flag instructs get to stop after downloading the packages; that is,
|
||||
it instructs get not to install the packages.
|
||||
|
||||
The -fix flag instructs get to run the fix tool on the downloaded packages
|
||||
before resolving dependencies or building the code.
|
||||
|
||||
The -t flag instructs get to also download the packages required to build
|
||||
the tests for the specified packages.
|
||||
|
||||
The -u flag instructs get to use the network to update the named packages
|
||||
and their dependencies. By default, get uses the network to check out
|
||||
missing packages but does not use it to look for updates to existing packages.
|
||||
|
||||
Get also accepts build flags to control the installation. See 'go help build'.
|
||||
|
||||
When checking out or updating a package, get looks for a branch or tag
|
||||
that matches the locally installed version of Go. The most important
|
||||
rule is that if the local installation is running version "go1", get
|
||||
searches for a branch or tag named "go1". If no such version exists it
|
||||
retrieves the most recent version of the package.
|
||||
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
For more about how 'go get' finds source code to
|
||||
download, see 'go help importpath'.
|
||||
|
||||
See also: go build, go install, go clean.
|
||||
|
||||
|
||||
Compile and install packages and dependencies
|
||||
|
||||
Usage:
|
||||
|
||||
go install [build flags] [packages]
|
||||
|
||||
Install compiles and installs the packages named by the import paths,
|
||||
along with their dependencies.
|
||||
|
||||
For more about the build flags, see 'go help build'.
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
See also: go build, go get, go clean.
|
||||
|
||||
|
||||
List packages
|
||||
|
||||
Usage:
|
||||
|
||||
go list [-e] [-f format] [-json] [build flags] [packages]
|
||||
|
||||
List lists the packages named by the import paths, one per line.
|
||||
|
||||
The default output shows the package import path:
|
||||
|
||||
code.google.com/p/google-api-go-client/books/v1
|
||||
code.google.com/p/goauth2/oauth
|
||||
code.google.com/p/sqlite
|
||||
|
||||
The -f flag specifies an alternate format for the list, using the
|
||||
syntax of package template. The default output is equivalent to -f
|
||||
'{{.ImportPath}}'. The struct being passed to the template is:
|
||||
|
||||
type Package struct {
|
||||
Dir string // directory containing package sources
|
||||
ImportPath string // import path of package in dir
|
||||
Name string // package name
|
||||
Doc string // package documentation string
|
||||
Target string // install path
|
||||
Goroot bool // is this package in the Go root?
|
||||
Standard bool // is this package part of the standard Go library?
|
||||
Stale bool // would 'go install' do anything for this package?
|
||||
Root string // Go root or Go path dir containing this package
|
||||
|
||||
// Source files
|
||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string // .go sources files that import "C"
|
||||
IgnoredGoFiles []string // .go sources ignored due to build constraints
|
||||
CFiles []string // .c source files
|
||||
CXXFiles []string // .cc, .cxx and .cpp source files
|
||||
MFiles []string // .m source files
|
||||
HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||
SFiles []string // .s source files
|
||||
SwigFiles []string // .swig files
|
||||
SwigCXXFiles []string // .swigcxx files
|
||||
SysoFiles []string // .syso object files to add to archive
|
||||
|
||||
// Cgo directives
|
||||
CgoCFLAGS []string // cgo: flags for C compiler
|
||||
CgoCPPFLAGS []string // cgo: flags for C preprocessor
|
||||
CgoCXXFLAGS []string // cgo: flags for C++ compiler
|
||||
CgoLDFLAGS []string // cgo: flags for linker
|
||||
CgoPkgConfig []string // cgo: pkg-config names
|
||||
|
||||
// Dependency information
|
||||
Imports []string // import paths used by this package
|
||||
Deps []string // all (recursively) imported dependencies
|
||||
|
||||
// Error information
|
||||
Incomplete bool // this package or a dependency has an error
|
||||
Error *PackageError // error loading package
|
||||
DepsErrors []*PackageError // errors loading dependencies
|
||||
|
||||
TestGoFiles []string // _test.go files in package
|
||||
TestImports []string // imports from TestGoFiles
|
||||
XTestGoFiles []string // _test.go files outside package
|
||||
XTestImports []string // imports from XTestGoFiles
|
||||
}
|
||||
|
||||
The template function "join" calls strings.Join.
|
||||
|
||||
The template function "context" returns the build context, defined as:
|
||||
|
||||
type Context struct {
|
||||
GOARCH string // target architecture
|
||||
GOOS string // target operating system
|
||||
GOROOT string // Go root
|
||||
GOPATH string // Go path
|
||||
CgoEnabled bool // whether cgo can be used
|
||||
UseAllFiles bool // use files regardless of +build lines, file names
|
||||
Compiler string // compiler to assume when computing target paths
|
||||
BuildTags []string // build constraints to match in +build lines
|
||||
ReleaseTags []string // releases the current release is compatible with
|
||||
InstallSuffix string // suffix to use in the name of the install dir
|
||||
}
|
||||
|
||||
For more information about the meaning of these fields see the documentation
|
||||
for the go/build package's Context type.
|
||||
|
||||
The -json flag causes the package data to be printed in JSON format
|
||||
instead of using the template format.
|
||||
|
||||
The -e flag changes the handling of erroneous packages, those that
|
||||
cannot be found or are malformed. By default, the list command
|
||||
prints an error to standard error for each erroneous package and
|
||||
omits the packages from consideration during the usual printing.
|
||||
With the -e flag, the list command never prints errors to standard
|
||||
error and instead processes the erroneous packages with the usual
|
||||
printing. Erroneous packages will have a non-empty ImportPath and
|
||||
a non-nil Error field; other information may or may not be missing
|
||||
(zeroed).
|
||||
|
||||
For more about build flags, see 'go help build'.
|
||||
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
|
||||
Compile and run Go program
|
||||
|
||||
Usage:
|
||||
|
||||
go run [build flags] [-exec xprog] gofiles... [arguments...]
|
||||
|
||||
Run compiles and runs the main package comprising the named Go source files.
|
||||
A Go source file is defined to be a file ending in a literal ".go" suffix.
|
||||
|
||||
By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
|
||||
If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
|
||||
If the -exec flag is not given, GOOS or GOARCH is different from the system
|
||||
default, and a program named go_$GOOS_$GOARCH_exec can be found
|
||||
on the current search path, 'go run' invokes the binary using that program,
|
||||
for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
|
||||
cross-compiled programs when a simulator or other execution method is
|
||||
available.
|
||||
|
||||
For more about build flags, see 'go help build'.
|
||||
|
||||
See also: go build.
|
||||
|
||||
|
||||
Test packages
|
||||
|
||||
Usage:
|
||||
|
||||
go test [-c] [-i] [build and test flags] [packages] [flags for test binary]
|
||||
|
||||
'Go test' automates testing the packages named by the import paths.
|
||||
It prints a summary of the test results in the format:
|
||||
|
||||
ok archive/tar 0.011s
|
||||
FAIL archive/zip 0.022s
|
||||
ok compress/gzip 0.033s
|
||||
...
|
||||
|
||||
followed by detailed output for each failed package.
|
||||
|
||||
'Go test' recompiles each package along with any files with names matching
|
||||
the file pattern "*_test.go".
|
||||
Files whose names begin with "_" (including "_test.go") or "." are ignored.
|
||||
These additional files can contain test functions, benchmark functions, and
|
||||
example functions. See 'go help testfunc' for more.
|
||||
Each listed package causes the execution of a separate test binary.
|
||||
|
||||
Test files that declare a package with the suffix "_test" will be compiled as a
|
||||
separate package, and then linked and run with the main test binary.
|
||||
|
||||
By default, go test needs no arguments. It compiles and tests the package
|
||||
with source in the current directory, including tests, and runs the tests.
|
||||
|
||||
The package is built in a temporary directory so it does not interfere with the
|
||||
non-test installation.
|
||||
|
||||
In addition to the build flags, the flags handled by 'go test' itself are:
|
||||
|
||||
-c Compile the test binary to pkg.test but do not run it.
|
||||
(Where pkg is the last element of the package's import path.)
|
||||
|
||||
-i
|
||||
Install packages that are dependencies of the test.
|
||||
Do not run the test.
|
||||
|
||||
-exec xprog
|
||||
Run the test binary using xprog. The behavior is the same as
|
||||
in 'go run'. See 'go help run' for details.
|
||||
|
||||
The test binary also accepts flags that control execution of the test; these
|
||||
flags are also accessible by 'go test'. See 'go help testflag' for details.
|
||||
|
||||
If the test binary needs any other flags, they should be presented after the
|
||||
package names. The go tool treats as a flag the first argument that begins with
|
||||
a minus sign that it does not recognize itself; that argument and all subsequent
|
||||
arguments are passed as arguments to the test binary.
|
||||
|
||||
For more about build flags, see 'go help build'.
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
See also: go build, go vet.
|
||||
|
||||
|
||||
Run specified go tool
|
||||
|
||||
Usage:
|
||||
|
||||
go tool [-n] command [args...]
|
||||
|
||||
Tool runs the go tool command identified by the arguments.
|
||||
With no arguments it prints the list of known tools.
|
||||
|
||||
The -n flag causes tool to print the command that would be
|
||||
executed but not execute it.
|
||||
|
||||
For more about each tool command, see 'go tool command -h'.
|
||||
|
||||
|
||||
Print Go version
|
||||
|
||||
Usage:
|
||||
|
||||
go version
|
||||
|
||||
Version prints the Go version, as reported by runtime.Version.
|
||||
|
||||
|
||||
Run go tool vet on packages
|
||||
|
||||
Usage:
|
||||
|
||||
go vet [-n] [-x] [packages]
|
||||
|
||||
Vet runs the Go vet command on the packages named by the import paths.
|
||||
|
||||
For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'.
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
To run the vet tool with specific options, run 'go tool vet'.
|
||||
|
||||
The -n flag prints commands that would be executed.
|
||||
The -x flag prints commands as they are executed.
|
||||
|
||||
See also: go fmt, go fix.
|
||||
|
||||
|
||||
Calling between Go and C
|
||||
|
||||
There are two different ways to call between Go and C/C++ code.
|
||||
|
||||
The first is the cgo tool, which is part of the Go distribution. For
|
||||
information on how to use it see the cgo documentation (godoc cmd/cgo).
|
||||
|
||||
The second is the SWIG program, which is a general tool for
|
||||
interfacing between languages. For information on SWIG see
|
||||
http://swig.org/. When running go build, any file with a .swig
|
||||
extension will be passed to SWIG. Any file with a .swigcxx extension
|
||||
will be passed to SWIG with the -c++ option.
|
||||
|
||||
When either cgo or SWIG is used, go build will pass any .c, .m, .s,
|
||||
or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
|
||||
compiler. The CC or CXX environment variables may be set to determine
|
||||
the C or C++ compiler, respectively, to use.
|
||||
|
||||
|
||||
File types
|
||||
|
||||
The go command examines the contents of a restricted set of files
|
||||
in each directory. It identifies which files to examine based on
|
||||
the extension of the file name. These extensions are:
|
||||
|
||||
.go
|
||||
Go source files.
|
||||
.c, .h
|
||||
C source files.
|
||||
If the package uses cgo, these will be compiled with the
|
||||
OS-native compiler (typically gcc); otherwise they will be
|
||||
compiled with the Go-specific support compiler,
|
||||
5c, 6c, or 8c, etc. as appropriate.
|
||||
.cc, .cpp, .cxx, .hh, .hpp, .hxx
|
||||
C++ source files. Only useful with cgo or SWIG, and always
|
||||
compiled with the OS-native compiler.
|
||||
.m
|
||||
Objective-C source files. Only useful with cgo, and always
|
||||
compiled with the OS-native compiler.
|
||||
.s, .S
|
||||
Assembler source files.
|
||||
If the package uses cgo, these will be assembled with the
|
||||
OS-native assembler (typically gcc (sic)); otherwise they
|
||||
will be assembled with the Go-specific support assembler,
|
||||
5a, 6a, or 8a, etc., as appropriate.
|
||||
.swig, .swigcxx
|
||||
SWIG definition files.
|
||||
.syso
|
||||
System object files.
|
||||
|
||||
Files of each of these types except .syso may contain build
|
||||
constraints, but the go command stops scanning for build constraints
|
||||
at the first item in the file that is not a blank line or //-style
|
||||
line comment.
|
||||
|
||||
|
||||
GOPATH environment variable
|
||||
|
||||
The Go path is used to resolve import statements.
|
||||
It is implemented by and documented in the go/build package.
|
||||
|
||||
The GOPATH environment variable lists places to look for Go code.
|
||||
On Unix, the value is a colon-separated string.
|
||||
On Windows, the value is a semicolon-separated string.
|
||||
On Plan 9, the value is a list.
|
||||
|
||||
GOPATH must be set to get, build and install packages outside the
|
||||
standard Go tree.
|
||||
|
||||
Each directory listed in GOPATH must have a prescribed structure:
|
||||
|
||||
The src/ directory holds source code. The path below 'src'
|
||||
determines the import path or executable name.
|
||||
|
||||
The pkg/ directory holds installed package objects.
|
||||
As in the Go tree, each target operating system and
|
||||
architecture pair has its own subdirectory of pkg
|
||||
(pkg/GOOS_GOARCH).
|
||||
|
||||
If DIR is a directory listed in the GOPATH, a package with
|
||||
source in DIR/src/foo/bar can be imported as "foo/bar" and
|
||||
has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
|
||||
|
||||
The bin/ directory holds compiled commands.
|
||||
Each command is named for its source directory, but only
|
||||
the final element, not the entire path. That is, the
|
||||
command with source in DIR/src/foo/quux is installed into
|
||||
DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
|
||||
so that you can add DIR/bin to your PATH to get at the
|
||||
installed commands. If the GOBIN environment variable is
|
||||
set, commands are installed to the directory it names instead
|
||||
of DIR/bin.
|
||||
|
||||
Here's an example directory layout:
|
||||
|
||||
GOPATH=/home/user/gocode
|
||||
|
||||
/home/user/gocode/
|
||||
src/
|
||||
foo/
|
||||
bar/ (go code in package bar)
|
||||
x.go
|
||||
quux/ (go code in package main)
|
||||
y.go
|
||||
bin/
|
||||
quux (installed command)
|
||||
pkg/
|
||||
linux_amd64/
|
||||
foo/
|
||||
bar.a (installed package object)
|
||||
|
||||
Go searches each directory listed in GOPATH to find source code,
|
||||
but new packages are always downloaded into the first directory
|
||||
in the list.
|
||||
|
||||
|
||||
Import path syntax
|
||||
|
||||
An import path (see 'go help packages') denotes a package
|
||||
stored in the local file system. In general, an import path denotes
|
||||
either a standard package (such as "unicode/utf8") or a package
|
||||
found in one of the work spaces (see 'go help gopath').
|
||||
|
||||
Relative import paths
|
||||
|
||||
An import path beginning with ./ or ../ is called a relative path.
|
||||
The toolchain supports relative import paths as a shortcut in two ways.
|
||||
|
||||
First, a relative path can be used as a shorthand on the command line.
|
||||
If you are working in the directory containing the code imported as
|
||||
"unicode" and want to run the tests for "unicode/utf8", you can type
|
||||
"go test ./utf8" instead of needing to specify the full path.
|
||||
Similarly, in the reverse situation, "go test .." will test "unicode" from
|
||||
the "unicode/utf8" directory. Relative patterns are also allowed, like
|
||||
"go test ./..." to test all subdirectories. See 'go help packages' for details
|
||||
on the pattern syntax.
|
||||
|
||||
Second, if you are compiling a Go program not in a work space,
|
||||
you can use a relative path in an import statement in that program
|
||||
to refer to nearby code also not in a work space.
|
||||
This makes it easy to experiment with small multipackage programs
|
||||
outside of the usual work spaces, but such programs cannot be
|
||||
installed with "go install" (there is no work space in which to install them),
|
||||
so they are rebuilt from scratch each time they are built.
|
||||
To avoid ambiguity, Go programs cannot use relative import paths
|
||||
within a work space.
|
||||
|
||||
Remote import paths
|
||||
|
||||
Certain import paths also
|
||||
describe how to obtain the source code for the package using
|
||||
a revision control system.
|
||||
|
||||
A few common code hosting sites have special syntax:
|
||||
|
||||
Bitbucket (Git, Mercurial)
|
||||
|
||||
import "bitbucket.org/user/project"
|
||||
import "bitbucket.org/user/project/sub/directory"
|
||||
|
||||
GitHub (Git)
|
||||
|
||||
import "github.com/user/project"
|
||||
import "github.com/user/project/sub/directory"
|
||||
|
||||
Google Code Project Hosting (Git, Mercurial, Subversion)
|
||||
|
||||
import "code.google.com/p/project"
|
||||
import "code.google.com/p/project/sub/directory"
|
||||
|
||||
import "code.google.com/p/project.subrepository"
|
||||
import "code.google.com/p/project.subrepository/sub/directory"
|
||||
|
||||
Launchpad (Bazaar)
|
||||
|
||||
import "launchpad.net/project"
|
||||
import "launchpad.net/project/series"
|
||||
import "launchpad.net/project/series/sub/directory"
|
||||
|
||||
import "launchpad.net/~user/project/branch"
|
||||
import "launchpad.net/~user/project/branch/sub/directory"
|
||||
|
||||
For code hosted on other servers, import paths may either be qualified
|
||||
with the version control type, or the go tool can dynamically fetch
|
||||
the import path over https/http and discover where the code resides
|
||||
from a <meta> tag in the HTML.
|
||||
|
||||
To declare the code location, an import path of the form
|
||||
|
||||
repository.vcs/path
|
||||
|
||||
specifies the given repository, with or without the .vcs suffix,
|
||||
using the named version control system, and then the path inside
|
||||
that repository. The supported version control systems are:
|
||||
|
||||
Bazaar .bzr
|
||||
Git .git
|
||||
Mercurial .hg
|
||||
Subversion .svn
|
||||
|
||||
For example,
|
||||
|
||||
import "example.org/user/foo.hg"
|
||||
|
||||
denotes the root directory of the Mercurial repository at
|
||||
example.org/user/foo or foo.hg, and
|
||||
|
||||
import "example.org/repo.git/foo/bar"
|
||||
|
||||
denotes the foo/bar directory of the Git repository at
|
||||
example.org/repo or repo.git.
|
||||
|
||||
When a version control system supports multiple protocols,
|
||||
each is tried in turn when downloading. For example, a Git
|
||||
download tries git://, then https://, then http://.
|
||||
|
||||
If the import path is not a known code hosting site and also lacks a
|
||||
version control qualifier, the go tool attempts to fetch the import
|
||||
over https/http and looks for a <meta> tag in the document's HTML
|
||||
<head>.
|
||||
|
||||
The meta tag has the form:
|
||||
|
||||
<meta name="go-import" content="import-prefix vcs repo-root">
|
||||
|
||||
The import-prefix is the import path corresponding to the repository
|
||||
root. It must be a prefix or an exact match of the package being
|
||||
fetched with "go get". If it's not an exact match, another http
|
||||
request is made at the prefix to verify the <meta> tags match.
|
||||
|
||||
The vcs is one of "git", "hg", "svn", etc,
|
||||
|
||||
The repo-root is the root of the version control system
|
||||
containing a scheme and not containing a .vcs qualifier.
|
||||
|
||||
For example,
|
||||
|
||||
import "example.org/pkg/foo"
|
||||
|
||||
will result in the following request(s):
|
||||
|
||||
https://example.org/pkg/foo?go-get=1 (preferred)
|
||||
http://example.org/pkg/foo?go-get=1 (fallback)
|
||||
|
||||
If that page contains the meta tag
|
||||
|
||||
<meta name="go-import" content="example.org git https://code.org/r/p/exproj">
|
||||
|
||||
the go tool will verify that https://example.org/?go-get=1 contains the
|
||||
same meta tag and then git clone https://code.org/r/p/exproj into
|
||||
GOPATH/src/example.org.
|
||||
|
||||
New downloaded packages are written to the first directory
|
||||
listed in the GOPATH environment variable (see 'go help gopath').
|
||||
|
||||
The go command attempts to download the version of the
|
||||
package appropriate for the Go release being used.
|
||||
Run 'go help install' for more.
|
||||
|
||||
|
||||
Description of package lists
|
||||
|
||||
Many commands apply to a set of packages:
|
||||
|
||||
go action [packages]
|
||||
|
||||
Usually, [packages] is a list of import paths.
|
||||
|
||||
An import path that is a rooted path or that begins with
|
||||
a . or .. element is interpreted as a file system path and
|
||||
denotes the package in that directory.
|
||||
|
||||
Otherwise, the import path P denotes the package found in
|
||||
the directory DIR/src/P for some DIR listed in the GOPATH
|
||||
environment variable (see 'go help gopath').
|
||||
|
||||
If no import paths are given, the action applies to the
|
||||
package in the current directory.
|
||||
|
||||
There are three reserved names for paths that should not be used
|
||||
for packages to be built with the go tool:
|
||||
|
||||
- "main" denotes the top-level package in a stand-alone executable.
|
||||
|
||||
- "all" expands to all package directories found in all the GOPATH
|
||||
trees. For example, 'go list all' lists all the packages on the local
|
||||
system.
|
||||
|
||||
- "std" is like all but expands to just the packages in the standard
|
||||
Go library.
|
||||
|
||||
An import path is a pattern if it includes one or more "..." wildcards,
|
||||
each of which can match any string, including the empty string and
|
||||
strings containing slashes. Such a pattern expands to all package
|
||||
directories found in the GOPATH trees with names matching the
|
||||
patterns. As a special case, x/... matches x as well as x's subdirectories.
|
||||
For example, net/... expands to net and packages in its subdirectories.
|
||||
|
||||
An import path can also name a package to be downloaded from
|
||||
a remote repository. Run 'go help importpath' for details.
|
||||
|
||||
Every package in a program must have a unique import path.
|
||||
By convention, this is arranged by starting each path with a
|
||||
unique prefix that belongs to you. For example, paths used
|
||||
internally at Google all begin with 'google', and paths
|
||||
denoting remote repositories begin with the path to the code,
|
||||
such as 'code.google.com/p/project'.
|
||||
|
||||
As a special case, if the package list is a list of .go files from a
|
||||
single directory, the command is applied to a single synthesized
|
||||
package made up of exactly those files, ignoring any build constraints
|
||||
in those files and ignoring any other files in the directory.
|
||||
|
||||
File names that begin with "." or "_" are ignored by the go tool.
|
||||
|
||||
|
||||
Description of testing flags
|
||||
|
||||
The 'go test' command takes both flags that apply to 'go test' itself
|
||||
and flags that apply to the resulting test binary.
|
||||
|
||||
Several of the flags control profiling and write an execution profile
|
||||
suitable for "go tool pprof"; run "go tool pprof help" for more
|
||||
information. The --alloc_space, --alloc_objects, and --show_bytes
|
||||
options of pprof control how the information is presented.
|
||||
|
||||
The following flags are recognized by the 'go test' command and
|
||||
control the execution of any test:
|
||||
|
||||
-bench regexp
|
||||
Run benchmarks matching the regular expression.
|
||||
By default, no benchmarks run. To run all benchmarks,
|
||||
use '-bench .' or '-bench=.'.
|
||||
|
||||
-benchmem
|
||||
Print memory allocation statistics for benchmarks.
|
||||
|
||||
-benchtime t
|
||||
Run enough iterations of each benchmark to take t, specified
|
||||
as a time.Duration (for example, -benchtime 1h30s).
|
||||
The default is 1 second (1s).
|
||||
|
||||
-blockprofile block.out
|
||||
Write a goroutine blocking profile to the specified file
|
||||
when all tests are complete.
|
||||
|
||||
-blockprofilerate n
|
||||
Control the detail provided in goroutine blocking profiles by
|
||||
calling runtime.SetBlockProfileRate with n.
|
||||
See 'godoc runtime SetBlockProfileRate'.
|
||||
The profiler aims to sample, on average, one blocking event every
|
||||
n nanoseconds the program spends blocked. By default,
|
||||
if -test.blockprofile is set without this flag, all blocking events
|
||||
are recorded, equivalent to -test.blockprofilerate=1.
|
||||
|
||||
-cover
|
||||
Enable coverage analysis.
|
||||
|
||||
-covermode set,count,atomic
|
||||
Set the mode for coverage analysis for the package[s]
|
||||
being tested. The default is "set" unless -race is enabled,
|
||||
in which case it is "atomic".
|
||||
The values:
|
||||
set: bool: does this statement run?
|
||||
count: int: how many times does this statement run?
|
||||
atomic: int: count, but correct in multithreaded tests;
|
||||
significantly more expensive.
|
||||
Sets -cover.
|
||||
|
||||
-coverpkg pkg1,pkg2,pkg3
|
||||
Apply coverage analysis in each test to the given list of packages.
|
||||
The default is for each test to analyze only the package being tested.
|
||||
Packages are specified as import paths.
|
||||
Sets -cover.
|
||||
|
||||
-coverprofile cover.out
|
||||
Write a coverage profile to the specified file after all tests
|
||||
have passed.
|
||||
Sets -cover.
|
||||
|
||||
-cpu 1,2,4
|
||||
Specify a list of GOMAXPROCS values for which the tests or
|
||||
benchmarks should be executed. The default is the current value
|
||||
of GOMAXPROCS.
|
||||
|
||||
-cpuprofile cpu.out
|
||||
Write a CPU profile to the specified file before exiting.
|
||||
|
||||
-memprofile mem.out
|
||||
Write a memory profile to the specified file after all tests
|
||||
have passed.
|
||||
|
||||
-memprofilerate n
|
||||
Enable more precise (and expensive) memory profiles by setting
|
||||
runtime.MemProfileRate. See 'godoc runtime MemProfileRate'.
|
||||
To profile all memory allocations, use -test.memprofilerate=1
|
||||
and pass --alloc_space flag to the pprof tool.
|
||||
|
||||
-outputdir directory
|
||||
Place output files from profiling in the specified directory,
|
||||
by default the directory in which "go test" is running.
|
||||
|
||||
-parallel n
|
||||
Allow parallel execution of test functions that call t.Parallel.
|
||||
The value of this flag is the maximum number of tests to run
|
||||
simultaneously; by default, it is set to the value of GOMAXPROCS.
|
||||
|
||||
-run regexp
|
||||
Run only those tests and examples matching the regular
|
||||
expression.
|
||||
|
||||
-short
|
||||
Tell long-running tests to shorten their run time.
|
||||
It is off by default but set during all.bash so that installing
|
||||
the Go tree can run a sanity check but not spend time running
|
||||
exhaustive tests.
|
||||
|
||||
-timeout t
|
||||
If a test runs longer than t, panic.
|
||||
|
||||
-v
|
||||
Verbose output: log all tests as they are run. Also print all
|
||||
text from Log and Logf calls even if the test succeeds.
|
||||
|
||||
The test binary, called pkg.test where pkg is the name of the
|
||||
directory containing the package sources, can be invoked directly
|
||||
after building it with 'go test -c'. When invoking the test binary
|
||||
directly, each of the standard flag names must be prefixed with 'test.',
|
||||
as in -test.run=TestMyFunc or -test.v.
|
||||
|
||||
When running 'go test', flags not listed above are passed through
|
||||
unaltered. For instance, the command
|
||||
|
||||
go test -x -v -cpuprofile=prof.out -dir=testdata -update
|
||||
|
||||
will compile the test binary and then run it as
|
||||
|
||||
pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
|
||||
|
||||
The test flags that generate profiles (other than for coverage) also
|
||||
leave the test binary in pkg.test for use when analyzing the profiles.
|
||||
|
||||
Flags not recognized by 'go test' must be placed after any specified packages.
|
||||
|
||||
|
||||
Description of testing functions
|
||||
|
||||
The 'go test' command expects to find test, benchmark, and example functions
|
||||
in the "*_test.go" files corresponding to the package under test.
|
||||
|
||||
A test function is one named TestXXX (where XXX is any alphanumeric string
|
||||
not starting with a lower case letter) and should have the signature,
|
||||
|
||||
func TestXXX(t *testing.T) { ... }
|
||||
|
||||
A benchmark function is one named BenchmarkXXX and should have the signature,
|
||||
|
||||
func BenchmarkXXX(b *testing.B) { ... }
|
||||
|
||||
An example function is similar to a test function but, instead of using
|
||||
*testing.T to report success or failure, prints output to os.Stdout.
|
||||
That output is compared against the function's "Output:" comment, which
|
||||
must be the last comment in the function body (see example below). An
|
||||
example with no such comment, or with no text after "Output:" is compiled
|
||||
but not executed.
|
||||
|
||||
Godoc displays the body of ExampleXXX to demonstrate the use
|
||||
of the function, constant, or variable XXX. An example of a method M with
|
||||
receiver type T or *T is named ExampleT_M. There may be multiple examples
|
||||
for a given function, constant, or variable, distinguished by a trailing _xxx,
|
||||
where xxx is a suffix not beginning with an upper case letter.
|
||||
|
||||
Here is an example of an example:
|
||||
|
||||
func ExamplePrintln() {
|
||||
Println("The output of\nthis example.")
|
||||
// Output: The output of
|
||||
// this example.
|
||||
}
|
||||
|
||||
The entire test file is presented as the example when it contains a single
|
||||
example function, at least one other function, type, variable, or constant
|
||||
declaration, and no test or benchmark functions.
|
||||
|
||||
See the documentation of the testing package for more information.
|
||||
|
||||
|
||||
*/
|
||||
package main
|
112
libgo/go/cmd/go/env.go
Normal file
112
libgo/go/cmd/go/env.go
Normal file
@ -0,0 +1,112 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var cmdEnv = &Command{
|
||||
Run: runEnv,
|
||||
UsageLine: "env [var ...]",
|
||||
Short: "print Go environment information",
|
||||
Long: `
|
||||
Env prints Go environment information.
|
||||
|
||||
By default env prints information as a shell script
|
||||
(on Windows, a batch file). If one or more variable
|
||||
names is given as arguments, env prints the value of
|
||||
each named variable on its own line.
|
||||
`,
|
||||
}
|
||||
|
||||
type envVar struct {
|
||||
name, value string
|
||||
}
|
||||
|
||||
func mkEnv() []envVar {
|
||||
var b builder
|
||||
b.init()
|
||||
|
||||
env := []envVar{
|
||||
{"GOARCH", goarch},
|
||||
{"GOBIN", gobin},
|
||||
{"GOCHAR", archChar},
|
||||
{"GOEXE", exeSuffix},
|
||||
{"GOHOSTARCH", runtime.GOARCH},
|
||||
{"GOHOSTOS", runtime.GOOS},
|
||||
{"GOOS", goos},
|
||||
{"GOPATH", os.Getenv("GOPATH")},
|
||||
{"GORACE", os.Getenv("GORACE")},
|
||||
{"GOROOT", goroot},
|
||||
{"GOTOOLDIR", toolDir},
|
||||
|
||||
// disable escape codes in clang errors
|
||||
{"TERM", "dumb"},
|
||||
}
|
||||
|
||||
if goos != "plan9" {
|
||||
cmd := b.gccCmd(".")
|
||||
env = append(env, envVar{"CC", cmd[0]})
|
||||
env = append(env, envVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")})
|
||||
cmd = b.gxxCmd(".")
|
||||
env = append(env, envVar{"CXX", cmd[0]})
|
||||
}
|
||||
|
||||
if buildContext.CgoEnabled {
|
||||
env = append(env, envVar{"CGO_ENABLED", "1"})
|
||||
} else {
|
||||
env = append(env, envVar{"CGO_ENABLED", "0"})
|
||||
}
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
func findEnv(env []envVar, name string) string {
|
||||
for _, e := range env {
|
||||
if e.name == name {
|
||||
return e.value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func runEnv(cmd *Command, args []string) {
|
||||
env := mkEnv()
|
||||
if len(args) > 0 {
|
||||
for _, name := range args {
|
||||
fmt.Printf("%s\n", findEnv(env, name))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for _, e := range env {
|
||||
if e.name != "TERM" {
|
||||
switch runtime.GOOS {
|
||||
default:
|
||||
fmt.Printf("%s=\"%s\"\n", e.name, e.value)
|
||||
case "plan9":
|
||||
if strings.IndexByte(e.value, '\x00') < 0 {
|
||||
fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
|
||||
} else {
|
||||
v := strings.Split(e.value, "\x00")
|
||||
fmt.Printf("%s=(", e.name)
|
||||
for x, s := range v {
|
||||
if x > 0 {
|
||||
fmt.Printf(" ")
|
||||
}
|
||||
fmt.Printf("%s", s)
|
||||
}
|
||||
fmt.Printf(")\n")
|
||||
}
|
||||
case "windows":
|
||||
fmt.Printf("set %s=%s\n", e.name, e.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
30
libgo/go/cmd/go/fix.go
Normal file
30
libgo/go/cmd/go/fix.go
Normal file
@ -0,0 +1,30 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
var cmdFix = &Command{
|
||||
Run: runFix,
|
||||
UsageLine: "fix [packages]",
|
||||
Short: "run go tool fix on packages",
|
||||
Long: `
|
||||
Fix runs the Go fix command on the packages named by the import paths.
|
||||
|
||||
For more about fix, see 'godoc fix'.
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
To run fix with specific options, run 'go tool fix'.
|
||||
|
||||
See also: go fmt, go vet.
|
||||
`,
|
||||
}
|
||||
|
||||
func runFix(cmd *Command, args []string) {
|
||||
for _, pkg := range packages(args) {
|
||||
// Use pkg.gofiles instead of pkg.Dir so that
|
||||
// the command only applies to this package,
|
||||
// not to packages in subdirectories.
|
||||
run(stringList(tool("fix"), relPaths(pkg.allgofiles)))
|
||||
}
|
||||
}
|
38
libgo/go/cmd/go/fmt.go
Normal file
38
libgo/go/cmd/go/fmt.go
Normal file
@ -0,0 +1,38 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
func init() {
|
||||
addBuildFlagsNX(cmdFmt)
|
||||
}
|
||||
|
||||
var cmdFmt = &Command{
|
||||
Run: runFmt,
|
||||
UsageLine: "fmt [-n] [-x] [packages]",
|
||||
Short: "run gofmt on package sources",
|
||||
Long: `
|
||||
Fmt runs the command 'gofmt -l -w' on the packages named
|
||||
by the import paths. It prints the names of the files that are modified.
|
||||
|
||||
For more about gofmt, see 'godoc gofmt'.
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
The -n flag prints commands that would be executed.
|
||||
The -x flag prints commands as they are executed.
|
||||
|
||||
To run gofmt with specific options, run gofmt itself.
|
||||
|
||||
See also: go fix, go vet.
|
||||
`,
|
||||
}
|
||||
|
||||
func runFmt(cmd *Command, args []string) {
|
||||
for _, pkg := range packages(args) {
|
||||
// Use pkg.gofiles instead of pkg.Dir so that
|
||||
// the command only applies to this package,
|
||||
// not to packages in subdirectories.
|
||||
run(stringList("gofmt", "-l", "-w", relPaths(pkg.allgofiles)))
|
||||
}
|
||||
}
|
429
libgo/go/cmd/go/get.go
Normal file
429
libgo/go/cmd/go/get.go
Normal file
@ -0,0 +1,429 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var cmdGet = &Command{
|
||||
UsageLine: "get [-d] [-fix] [-t] [-u] [build flags] [packages]",
|
||||
Short: "download and install packages and dependencies",
|
||||
Long: `
|
||||
Get downloads and installs the packages named by the import paths,
|
||||
along with their dependencies.
|
||||
|
||||
The -d flag instructs get to stop after downloading the packages; that is,
|
||||
it instructs get not to install the packages.
|
||||
|
||||
The -fix flag instructs get to run the fix tool on the downloaded packages
|
||||
before resolving dependencies or building the code.
|
||||
|
||||
The -t flag instructs get to also download the packages required to build
|
||||
the tests for the specified packages.
|
||||
|
||||
The -u flag instructs get to use the network to update the named packages
|
||||
and their dependencies. By default, get uses the network to check out
|
||||
missing packages but does not use it to look for updates to existing packages.
|
||||
|
||||
Get also accepts build flags to control the installation. See 'go help build'.
|
||||
|
||||
When checking out or updating a package, get looks for a branch or tag
|
||||
that matches the locally installed version of Go. The most important
|
||||
rule is that if the local installation is running version "go1", get
|
||||
searches for a branch or tag named "go1". If no such version exists it
|
||||
retrieves the most recent version of the package.
|
||||
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
For more about how 'go get' finds source code to
|
||||
download, see 'go help importpath'.
|
||||
|
||||
See also: go build, go install, go clean.
|
||||
`,
|
||||
}
|
||||
|
||||
var getD = cmdGet.Flag.Bool("d", false, "")
|
||||
var getT = cmdGet.Flag.Bool("t", false, "")
|
||||
var getU = cmdGet.Flag.Bool("u", false, "")
|
||||
var getFix = cmdGet.Flag.Bool("fix", false, "")
|
||||
|
||||
func init() {
|
||||
addBuildFlags(cmdGet)
|
||||
cmdGet.Run = runGet // break init loop
|
||||
}
|
||||
|
||||
func runGet(cmd *Command, args []string) {
|
||||
// Phase 1. Download/update.
|
||||
var stk importStack
|
||||
for _, arg := range downloadPaths(args) {
|
||||
download(arg, &stk, *getT)
|
||||
}
|
||||
exitIfErrors()
|
||||
|
||||
// Phase 2. Rescan packages and re-evaluate args list.
|
||||
|
||||
// Code we downloaded and all code that depends on it
|
||||
// needs to be evicted from the package cache so that
|
||||
// the information will be recomputed. Instead of keeping
|
||||
// track of the reverse dependency information, evict
|
||||
// everything.
|
||||
for name := range packageCache {
|
||||
delete(packageCache, name)
|
||||
}
|
||||
|
||||
args = importPaths(args)
|
||||
|
||||
// Phase 3. Install.
|
||||
if *getD {
|
||||
// Download only.
|
||||
// Check delayed until now so that importPaths
|
||||
// has a chance to print errors.
|
||||
return
|
||||
}
|
||||
|
||||
runInstall(cmd, args)
|
||||
}
|
||||
|
||||
// downloadPaths prepares the list of paths to pass to download.
|
||||
// It expands ... patterns that can be expanded. If there is no match
|
||||
// for a particular pattern, downloadPaths leaves it in the result list,
|
||||
// in the hope that we can figure out the repository from the
|
||||
// initial ...-free prefix.
|
||||
func downloadPaths(args []string) []string {
|
||||
args = importPathsNoDotExpansion(args)
|
||||
var out []string
|
||||
for _, a := range args {
|
||||
if strings.Contains(a, "...") {
|
||||
var expand []string
|
||||
// Use matchPackagesInFS to avoid printing
|
||||
// warnings. They will be printed by the
|
||||
// eventual call to importPaths instead.
|
||||
if build.IsLocalImport(a) {
|
||||
expand = matchPackagesInFS(a)
|
||||
} else {
|
||||
expand = matchPackages(a)
|
||||
}
|
||||
if len(expand) > 0 {
|
||||
out = append(out, expand...)
|
||||
continue
|
||||
}
|
||||
}
|
||||
out = append(out, a)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// downloadCache records the import paths we have already
|
||||
// considered during the download, to avoid duplicate work when
|
||||
// there is more than one dependency sequence leading to
|
||||
// a particular package.
|
||||
var downloadCache = map[string]bool{}
|
||||
|
||||
// downloadRootCache records the version control repository
|
||||
// root directories we have already considered during the download.
|
||||
// For example, all the packages in the code.google.com/p/codesearch repo
|
||||
// share the same root (the directory for that path), and we only need
|
||||
// to run the hg commands to consider each repository once.
|
||||
var downloadRootCache = map[string]bool{}
|
||||
|
||||
// download runs the download half of the get command
|
||||
// for the package named by the argument.
|
||||
func download(arg string, stk *importStack, getTestDeps bool) {
|
||||
p := loadPackage(arg, stk)
|
||||
if p.Error != nil && p.Error.hard {
|
||||
errorf("%s", p.Error)
|
||||
return
|
||||
}
|
||||
|
||||
// There's nothing to do if this is a package in the standard library.
|
||||
if p.Standard {
|
||||
return
|
||||
}
|
||||
|
||||
// Only process each package once.
|
||||
if downloadCache[arg] {
|
||||
return
|
||||
}
|
||||
downloadCache[arg] = true
|
||||
|
||||
pkgs := []*Package{p}
|
||||
wildcardOkay := len(*stk) == 0
|
||||
isWildcard := false
|
||||
|
||||
// Download if the package is missing, or update if we're using -u.
|
||||
if p.Dir == "" || *getU {
|
||||
// The actual download.
|
||||
stk.push(p.ImportPath)
|
||||
err := downloadPackage(p)
|
||||
if err != nil {
|
||||
errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
|
||||
stk.pop()
|
||||
return
|
||||
}
|
||||
|
||||
args := []string{arg}
|
||||
// If the argument has a wildcard in it, re-evaluate the wildcard.
|
||||
// We delay this until after reloadPackage so that the old entry
|
||||
// for p has been replaced in the package cache.
|
||||
if wildcardOkay && strings.Contains(arg, "...") {
|
||||
if build.IsLocalImport(arg) {
|
||||
args = matchPackagesInFS(arg)
|
||||
} else {
|
||||
args = matchPackages(arg)
|
||||
}
|
||||
isWildcard = true
|
||||
}
|
||||
|
||||
// Clear all relevant package cache entries before
|
||||
// doing any new loads.
|
||||
for _, arg := range args {
|
||||
p := packageCache[arg]
|
||||
if p != nil {
|
||||
delete(packageCache, p.Dir)
|
||||
delete(packageCache, p.ImportPath)
|
||||
}
|
||||
}
|
||||
|
||||
pkgs = pkgs[:0]
|
||||
for _, arg := range args {
|
||||
stk.push(arg)
|
||||
p := loadPackage(arg, stk)
|
||||
stk.pop()
|
||||
if p.Error != nil {
|
||||
errorf("%s", p.Error)
|
||||
continue
|
||||
}
|
||||
pkgs = append(pkgs, p)
|
||||
}
|
||||
}
|
||||
|
||||
// Process package, which might now be multiple packages
|
||||
// due to wildcard expansion.
|
||||
for _, p := range pkgs {
|
||||
if *getFix {
|
||||
run(stringList(tool("fix"), relPaths(p.allgofiles)))
|
||||
|
||||
// The imports might have changed, so reload again.
|
||||
p = reloadPackage(arg, stk)
|
||||
if p.Error != nil {
|
||||
errorf("%s", p.Error)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if isWildcard {
|
||||
// Report both the real package and the
|
||||
// wildcard in any error message.
|
||||
stk.push(p.ImportPath)
|
||||
}
|
||||
|
||||
// Process dependencies, now that we know what they are.
|
||||
for _, dep := range p.deps {
|
||||
// Don't get test dependencies recursively.
|
||||
download(dep.ImportPath, stk, false)
|
||||
}
|
||||
if getTestDeps {
|
||||
// Process test dependencies when -t is specified.
|
||||
// (Don't get test dependencies for test dependencies.)
|
||||
for _, path := range p.TestImports {
|
||||
download(path, stk, false)
|
||||
}
|
||||
for _, path := range p.XTestImports {
|
||||
download(path, stk, false)
|
||||
}
|
||||
}
|
||||
|
||||
if isWildcard {
|
||||
stk.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// downloadPackage runs the create or download command
|
||||
// to make the first copy of or update a copy of the given package.
|
||||
func downloadPackage(p *Package) error {
|
||||
var (
|
||||
vcs *vcsCmd
|
||||
repo, rootPath string
|
||||
err error
|
||||
)
|
||||
if p.build.SrcRoot != "" {
|
||||
// Directory exists. Look for checkout along path to src.
|
||||
vcs, rootPath, err = vcsForDir(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repo = "<local>" // should be unused; make distinctive
|
||||
} else {
|
||||
// Analyze the import path to determine the version control system,
|
||||
// repository, and the import path for the root of the repository.
|
||||
rr, err := repoRootForImportPath(p.ImportPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
|
||||
}
|
||||
|
||||
if p.build.SrcRoot == "" {
|
||||
// Package not found. Put in first directory of $GOPATH.
|
||||
list := filepath.SplitList(buildContext.GOPATH)
|
||||
if len(list) == 0 {
|
||||
return fmt.Errorf("cannot download, $GOPATH not set. For more details see: go help gopath")
|
||||
}
|
||||
// Guard against people setting GOPATH=$GOROOT.
|
||||
if list[0] == goroot {
|
||||
return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath")
|
||||
}
|
||||
p.build.SrcRoot = filepath.Join(list[0], "src")
|
||||
p.build.PkgRoot = filepath.Join(list[0], "pkg")
|
||||
}
|
||||
root := filepath.Join(p.build.SrcRoot, rootPath)
|
||||
// If we've considered this repository already, don't do it again.
|
||||
if downloadRootCache[root] {
|
||||
return nil
|
||||
}
|
||||
downloadRootCache[root] = true
|
||||
|
||||
if buildV {
|
||||
fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
|
||||
}
|
||||
|
||||
// Check that this is an appropriate place for the repo to be checked out.
|
||||
// The target directory must either not exist or have a repo checked out already.
|
||||
meta := filepath.Join(root, "."+vcs.cmd)
|
||||
st, err := os.Stat(meta)
|
||||
if err == nil && !st.IsDir() {
|
||||
return fmt.Errorf("%s exists but is not a directory", meta)
|
||||
}
|
||||
if err != nil {
|
||||
// Metadata directory does not exist. Prepare to checkout new copy.
|
||||
// Some version control tools require the target directory not to exist.
|
||||
// We require that too, just to avoid stepping on existing work.
|
||||
if _, err := os.Stat(root); err == nil {
|
||||
return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
|
||||
}
|
||||
// Some version control tools require the parent of the target to exist.
|
||||
parent, _ := filepath.Split(root)
|
||||
if err = os.MkdirAll(parent, 0777); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = vcs.create(root, repo); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Metadata directory does exist; download incremental updates.
|
||||
if err = vcs.download(root); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if buildN {
|
||||
// Do not show tag sync in -n; it's noise more than anything,
|
||||
// and since we're not running commands, no tag will be found.
|
||||
// But avoid printing nothing.
|
||||
fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Select and sync to appropriate version of the repository.
|
||||
tags, err := vcs.tags(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vers := runtime.Version()
|
||||
if i := strings.Index(vers, " "); i >= 0 {
|
||||
vers = vers[:i]
|
||||
}
|
||||
if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// goTag matches go release tags such as go1 and go1.2.3.
|
||||
// The numbers involved must be small (at most 4 digits),
|
||||
// have no unnecessary leading zeros, and the version cannot
|
||||
// end in .0 - it is go1, not go1.0 or go1.0.0.
|
||||
var goTag = regexp.MustCompile(
|
||||
`^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`,
|
||||
)
|
||||
|
||||
// selectTag returns the closest matching tag for a given version.
|
||||
// Closest means the latest one that is not after the current release.
|
||||
// Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
|
||||
// Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
|
||||
// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
|
||||
//
|
||||
// NOTE(rsc): Eventually we will need to decide on some logic here.
|
||||
// For now, there is only "go1". This matches the docs in go help get.
|
||||
func selectTag(goVersion string, tags []string) (match string) {
|
||||
for _, t := range tags {
|
||||
if t == "go1" {
|
||||
return "go1"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
||||
/*
|
||||
if goTag.MatchString(goVersion) {
|
||||
v := goVersion
|
||||
for _, t := range tags {
|
||||
if !goTag.MatchString(t) {
|
||||
continue
|
||||
}
|
||||
if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 {
|
||||
match = t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return match
|
||||
*/
|
||||
}
|
||||
|
||||
// cmpGoVersion returns -1, 0, +1 reporting whether
|
||||
// x < y, x == y, or x > y.
|
||||
func cmpGoVersion(x, y string) int {
|
||||
// Malformed strings compare less than well-formed strings.
|
||||
if !goTag.MatchString(x) {
|
||||
return -1
|
||||
}
|
||||
if !goTag.MatchString(y) {
|
||||
return +1
|
||||
}
|
||||
|
||||
// Compare numbers in sequence.
|
||||
xx := strings.Split(x[len("go"):], ".")
|
||||
yy := strings.Split(y[len("go"):], ".")
|
||||
|
||||
for i := 0; i < len(xx) && i < len(yy); i++ {
|
||||
// The Atoi are guaranteed to succeed
|
||||
// because the versions match goTag.
|
||||
xi, _ := strconv.Atoi(xx[i])
|
||||
yi, _ := strconv.Atoi(yy[i])
|
||||
if xi < yi {
|
||||
return -1
|
||||
} else if xi > yi {
|
||||
return +1
|
||||
}
|
||||
}
|
||||
|
||||
if len(xx) < len(yy) {
|
||||
return -1
|
||||
}
|
||||
if len(xx) > len(yy) {
|
||||
return +1
|
||||
}
|
||||
return 0
|
||||
}
|
10
libgo/go/cmd/go/go11.go
Normal file
10
libgo/go/cmd/go/go11.go
Normal file
@ -0,0 +1,10 @@
|
||||
// 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.
|
||||
|
||||
// +build go1.1
|
||||
|
||||
package main
|
||||
|
||||
// Test that go1.1 tag above is included in builds. main.go refers to this definition.
|
||||
const go11tag = true
|
337
libgo/go/cmd/go/help.go
Normal file
337
libgo/go/cmd/go/help.go
Normal file
@ -0,0 +1,337 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
var helpC = &Command{
|
||||
UsageLine: "c",
|
||||
Short: "calling between Go and C",
|
||||
Long: `
|
||||
There are two different ways to call between Go and C/C++ code.
|
||||
|
||||
The first is the cgo tool, which is part of the Go distribution. For
|
||||
information on how to use it see the cgo documentation (godoc cmd/cgo).
|
||||
|
||||
The second is the SWIG program, which is a general tool for
|
||||
interfacing between languages. For information on SWIG see
|
||||
http://swig.org/. When running go build, any file with a .swig
|
||||
extension will be passed to SWIG. Any file with a .swigcxx extension
|
||||
will be passed to SWIG with the -c++ option.
|
||||
|
||||
When either cgo or SWIG is used, go build will pass any .c, .m, .s,
|
||||
or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
|
||||
compiler. The CC or CXX environment variables may be set to determine
|
||||
the C or C++ compiler, respectively, to use.
|
||||
`,
|
||||
}
|
||||
|
||||
var helpPackages = &Command{
|
||||
UsageLine: "packages",
|
||||
Short: "description of package lists",
|
||||
Long: `
|
||||
Many commands apply to a set of packages:
|
||||
|
||||
go action [packages]
|
||||
|
||||
Usually, [packages] is a list of import paths.
|
||||
|
||||
An import path that is a rooted path or that begins with
|
||||
a . or .. element is interpreted as a file system path and
|
||||
denotes the package in that directory.
|
||||
|
||||
Otherwise, the import path P denotes the package found in
|
||||
the directory DIR/src/P for some DIR listed in the GOPATH
|
||||
environment variable (see 'go help gopath').
|
||||
|
||||
If no import paths are given, the action applies to the
|
||||
package in the current directory.
|
||||
|
||||
There are three reserved names for paths that should not be used
|
||||
for packages to be built with the go tool:
|
||||
|
||||
- "main" denotes the top-level package in a stand-alone executable.
|
||||
|
||||
- "all" expands to all package directories found in all the GOPATH
|
||||
trees. For example, 'go list all' lists all the packages on the local
|
||||
system.
|
||||
|
||||
- "std" is like all but expands to just the packages in the standard
|
||||
Go library.
|
||||
|
||||
An import path is a pattern if it includes one or more "..." wildcards,
|
||||
each of which can match any string, including the empty string and
|
||||
strings containing slashes. Such a pattern expands to all package
|
||||
directories found in the GOPATH trees with names matching the
|
||||
patterns. As a special case, x/... matches x as well as x's subdirectories.
|
||||
For example, net/... expands to net and packages in its subdirectories.
|
||||
|
||||
An import path can also name a package to be downloaded from
|
||||
a remote repository. Run 'go help importpath' for details.
|
||||
|
||||
Every package in a program must have a unique import path.
|
||||
By convention, this is arranged by starting each path with a
|
||||
unique prefix that belongs to you. For example, paths used
|
||||
internally at Google all begin with 'google', and paths
|
||||
denoting remote repositories begin with the path to the code,
|
||||
such as 'code.google.com/p/project'.
|
||||
|
||||
As a special case, if the package list is a list of .go files from a
|
||||
single directory, the command is applied to a single synthesized
|
||||
package made up of exactly those files, ignoring any build constraints
|
||||
in those files and ignoring any other files in the directory.
|
||||
|
||||
File names that begin with "." or "_" are ignored by the go tool.
|
||||
`,
|
||||
}
|
||||
|
||||
var helpImportPath = &Command{
|
||||
UsageLine: "importpath",
|
||||
Short: "import path syntax",
|
||||
Long: `
|
||||
|
||||
An import path (see 'go help packages') denotes a package
|
||||
stored in the local file system. In general, an import path denotes
|
||||
either a standard package (such as "unicode/utf8") or a package
|
||||
found in one of the work spaces (see 'go help gopath').
|
||||
|
||||
Relative import paths
|
||||
|
||||
An import path beginning with ./ or ../ is called a relative path.
|
||||
The toolchain supports relative import paths as a shortcut in two ways.
|
||||
|
||||
First, a relative path can be used as a shorthand on the command line.
|
||||
If you are working in the directory containing the code imported as
|
||||
"unicode" and want to run the tests for "unicode/utf8", you can type
|
||||
"go test ./utf8" instead of needing to specify the full path.
|
||||
Similarly, in the reverse situation, "go test .." will test "unicode" from
|
||||
the "unicode/utf8" directory. Relative patterns are also allowed, like
|
||||
"go test ./..." to test all subdirectories. See 'go help packages' for details
|
||||
on the pattern syntax.
|
||||
|
||||
Second, if you are compiling a Go program not in a work space,
|
||||
you can use a relative path in an import statement in that program
|
||||
to refer to nearby code also not in a work space.
|
||||
This makes it easy to experiment with small multipackage programs
|
||||
outside of the usual work spaces, but such programs cannot be
|
||||
installed with "go install" (there is no work space in which to install them),
|
||||
so they are rebuilt from scratch each time they are built.
|
||||
To avoid ambiguity, Go programs cannot use relative import paths
|
||||
within a work space.
|
||||
|
||||
Remote import paths
|
||||
|
||||
Certain import paths also
|
||||
describe how to obtain the source code for the package using
|
||||
a revision control system.
|
||||
|
||||
A few common code hosting sites have special syntax:
|
||||
|
||||
Bitbucket (Git, Mercurial)
|
||||
|
||||
import "bitbucket.org/user/project"
|
||||
import "bitbucket.org/user/project/sub/directory"
|
||||
|
||||
GitHub (Git)
|
||||
|
||||
import "github.com/user/project"
|
||||
import "github.com/user/project/sub/directory"
|
||||
|
||||
Google Code Project Hosting (Git, Mercurial, Subversion)
|
||||
|
||||
import "code.google.com/p/project"
|
||||
import "code.google.com/p/project/sub/directory"
|
||||
|
||||
import "code.google.com/p/project.subrepository"
|
||||
import "code.google.com/p/project.subrepository/sub/directory"
|
||||
|
||||
Launchpad (Bazaar)
|
||||
|
||||
import "launchpad.net/project"
|
||||
import "launchpad.net/project/series"
|
||||
import "launchpad.net/project/series/sub/directory"
|
||||
|
||||
import "launchpad.net/~user/project/branch"
|
||||
import "launchpad.net/~user/project/branch/sub/directory"
|
||||
|
||||
For code hosted on other servers, import paths may either be qualified
|
||||
with the version control type, or the go tool can dynamically fetch
|
||||
the import path over https/http and discover where the code resides
|
||||
from a <meta> tag in the HTML.
|
||||
|
||||
To declare the code location, an import path of the form
|
||||
|
||||
repository.vcs/path
|
||||
|
||||
specifies the given repository, with or without the .vcs suffix,
|
||||
using the named version control system, and then the path inside
|
||||
that repository. The supported version control systems are:
|
||||
|
||||
Bazaar .bzr
|
||||
Git .git
|
||||
Mercurial .hg
|
||||
Subversion .svn
|
||||
|
||||
For example,
|
||||
|
||||
import "example.org/user/foo.hg"
|
||||
|
||||
denotes the root directory of the Mercurial repository at
|
||||
example.org/user/foo or foo.hg, and
|
||||
|
||||
import "example.org/repo.git/foo/bar"
|
||||
|
||||
denotes the foo/bar directory of the Git repository at
|
||||
example.org/repo or repo.git.
|
||||
|
||||
When a version control system supports multiple protocols,
|
||||
each is tried in turn when downloading. For example, a Git
|
||||
download tries git://, then https://, then http://.
|
||||
|
||||
If the import path is not a known code hosting site and also lacks a
|
||||
version control qualifier, the go tool attempts to fetch the import
|
||||
over https/http and looks for a <meta> tag in the document's HTML
|
||||
<head>.
|
||||
|
||||
The meta tag has the form:
|
||||
|
||||
<meta name="go-import" content="import-prefix vcs repo-root">
|
||||
|
||||
The import-prefix is the import path corresponding to the repository
|
||||
root. It must be a prefix or an exact match of the package being
|
||||
fetched with "go get". If it's not an exact match, another http
|
||||
request is made at the prefix to verify the <meta> tags match.
|
||||
|
||||
The vcs is one of "git", "hg", "svn", etc,
|
||||
|
||||
The repo-root is the root of the version control system
|
||||
containing a scheme and not containing a .vcs qualifier.
|
||||
|
||||
For example,
|
||||
|
||||
import "example.org/pkg/foo"
|
||||
|
||||
will result in the following request(s):
|
||||
|
||||
https://example.org/pkg/foo?go-get=1 (preferred)
|
||||
http://example.org/pkg/foo?go-get=1 (fallback)
|
||||
|
||||
If that page contains the meta tag
|
||||
|
||||
<meta name="go-import" content="example.org git https://code.org/r/p/exproj">
|
||||
|
||||
the go tool will verify that https://example.org/?go-get=1 contains the
|
||||
same meta tag and then git clone https://code.org/r/p/exproj into
|
||||
GOPATH/src/example.org.
|
||||
|
||||
New downloaded packages are written to the first directory
|
||||
listed in the GOPATH environment variable (see 'go help gopath').
|
||||
|
||||
The go command attempts to download the version of the
|
||||
package appropriate for the Go release being used.
|
||||
Run 'go help install' for more.
|
||||
`,
|
||||
}
|
||||
|
||||
var helpGopath = &Command{
|
||||
UsageLine: "gopath",
|
||||
Short: "GOPATH environment variable",
|
||||
Long: `
|
||||
The Go path is used to resolve import statements.
|
||||
It is implemented by and documented in the go/build package.
|
||||
|
||||
The GOPATH environment variable lists places to look for Go code.
|
||||
On Unix, the value is a colon-separated string.
|
||||
On Windows, the value is a semicolon-separated string.
|
||||
On Plan 9, the value is a list.
|
||||
|
||||
GOPATH must be set to get, build and install packages outside the
|
||||
standard Go tree.
|
||||
|
||||
Each directory listed in GOPATH must have a prescribed structure:
|
||||
|
||||
The src/ directory holds source code. The path below 'src'
|
||||
determines the import path or executable name.
|
||||
|
||||
The pkg/ directory holds installed package objects.
|
||||
As in the Go tree, each target operating system and
|
||||
architecture pair has its own subdirectory of pkg
|
||||
(pkg/GOOS_GOARCH).
|
||||
|
||||
If DIR is a directory listed in the GOPATH, a package with
|
||||
source in DIR/src/foo/bar can be imported as "foo/bar" and
|
||||
has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
|
||||
|
||||
The bin/ directory holds compiled commands.
|
||||
Each command is named for its source directory, but only
|
||||
the final element, not the entire path. That is, the
|
||||
command with source in DIR/src/foo/quux is installed into
|
||||
DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
|
||||
so that you can add DIR/bin to your PATH to get at the
|
||||
installed commands. If the GOBIN environment variable is
|
||||
set, commands are installed to the directory it names instead
|
||||
of DIR/bin.
|
||||
|
||||
Here's an example directory layout:
|
||||
|
||||
GOPATH=/home/user/gocode
|
||||
|
||||
/home/user/gocode/
|
||||
src/
|
||||
foo/
|
||||
bar/ (go code in package bar)
|
||||
x.go
|
||||
quux/ (go code in package main)
|
||||
y.go
|
||||
bin/
|
||||
quux (installed command)
|
||||
pkg/
|
||||
linux_amd64/
|
||||
foo/
|
||||
bar.a (installed package object)
|
||||
|
||||
Go searches each directory listed in GOPATH to find source code,
|
||||
but new packages are always downloaded into the first directory
|
||||
in the list.
|
||||
`,
|
||||
}
|
||||
|
||||
var helpFileType = &Command{
|
||||
UsageLine: "filetype",
|
||||
Short: "file types",
|
||||
Long: `
|
||||
The go command examines the contents of a restricted set of files
|
||||
in each directory. It identifies which files to examine based on
|
||||
the extension of the file name. These extensions are:
|
||||
|
||||
.go
|
||||
Go source files.
|
||||
.c, .h
|
||||
C source files.
|
||||
If the package uses cgo, these will be compiled with the
|
||||
OS-native compiler (typically gcc); otherwise they will be
|
||||
compiled with the Go-specific support compiler,
|
||||
5c, 6c, or 8c, etc. as appropriate.
|
||||
.cc, .cpp, .cxx, .hh, .hpp, .hxx
|
||||
C++ source files. Only useful with cgo or SWIG, and always
|
||||
compiled with the OS-native compiler.
|
||||
.m
|
||||
Objective-C source files. Only useful with cgo, and always
|
||||
compiled with the OS-native compiler.
|
||||
.s, .S
|
||||
Assembler source files.
|
||||
If the package uses cgo, these will be assembled with the
|
||||
OS-native assembler (typically gcc (sic)); otherwise they
|
||||
will be assembled with the Go-specific support assembler,
|
||||
5a, 6a, or 8a, etc., as appropriate.
|
||||
.swig, .swigcxx
|
||||
SWIG definition files.
|
||||
.syso
|
||||
System object files.
|
||||
|
||||
Files of each of these types except .syso may contain build
|
||||
constraints, but the go command stops scanning for build constraints
|
||||
at the first item in the file that is not a blank line or //-style
|
||||
line comment.
|
||||
`,
|
||||
}
|
87
libgo/go/cmd/go/http.go
Normal file
87
libgo/go/cmd/go/http.go
Normal file
@ -0,0 +1,87 @@
|
||||
// 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 !cmd_go_bootstrap
|
||||
|
||||
// This code is compiled into the real 'go' binary, but it is not
|
||||
// compiled into the binary that is built during all.bash, so as
|
||||
// to avoid needing to build net (and thus use cgo) during the
|
||||
// bootstrap process.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// httpClient is the default HTTP client, but a variable so it can be
|
||||
// changed by tests, without modifying http.DefaultClient.
|
||||
var httpClient = http.DefaultClient
|
||||
|
||||
// httpGET returns the data from an HTTP GET request for the given URL.
|
||||
func httpGET(url string) ([]byte, error) {
|
||||
resp, err := httpClient.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("%s: %s", url, resp.Status)
|
||||
}
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %v", url, err)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// httpsOrHTTP returns the body of either the importPath's
|
||||
// https resource or, if unavailable, the http resource.
|
||||
func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) {
|
||||
fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
|
||||
u, err := url.Parse(scheme + "://" + importPath)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
u.RawQuery = "go-get=1"
|
||||
urlStr = u.String()
|
||||
if buildV {
|
||||
log.Printf("Fetching %s", urlStr)
|
||||
}
|
||||
res, err = httpClient.Get(urlStr)
|
||||
return
|
||||
}
|
||||
closeBody := func(res *http.Response) {
|
||||
if res != nil {
|
||||
res.Body.Close()
|
||||
}
|
||||
}
|
||||
urlStr, res, err := fetch("https")
|
||||
if err != nil || res.StatusCode != 200 {
|
||||
if buildV {
|
||||
if err != nil {
|
||||
log.Printf("https fetch failed.")
|
||||
} else {
|
||||
log.Printf("ignoring https fetch with status code %d", res.StatusCode)
|
||||
}
|
||||
}
|
||||
closeBody(res)
|
||||
urlStr, res, err = fetch("http")
|
||||
}
|
||||
if err != nil {
|
||||
closeBody(res)
|
||||
return "", nil, err
|
||||
}
|
||||
// Note: accepting a non-200 OK here, so people can serve a
|
||||
// meta import in their http 404 page.
|
||||
if buildV {
|
||||
log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
|
||||
}
|
||||
return urlStr, res.Body, nil
|
||||
}
|
208
libgo/go/cmd/go/list.go
Normal file
208
libgo/go/cmd/go/list.go
Normal file
@ -0,0 +1,208 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var cmdList = &Command{
|
||||
UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
|
||||
Short: "list packages",
|
||||
Long: `
|
||||
List lists the packages named by the import paths, one per line.
|
||||
|
||||
The default output shows the package import path:
|
||||
|
||||
code.google.com/p/google-api-go-client/books/v1
|
||||
code.google.com/p/goauth2/oauth
|
||||
code.google.com/p/sqlite
|
||||
|
||||
The -f flag specifies an alternate format for the list, using the
|
||||
syntax of package template. The default output is equivalent to -f
|
||||
'{{.ImportPath}}'. The struct being passed to the template is:
|
||||
|
||||
type Package struct {
|
||||
Dir string // directory containing package sources
|
||||
ImportPath string // import path of package in dir
|
||||
Name string // package name
|
||||
Doc string // package documentation string
|
||||
Target string // install path
|
||||
Goroot bool // is this package in the Go root?
|
||||
Standard bool // is this package part of the standard Go library?
|
||||
Stale bool // would 'go install' do anything for this package?
|
||||
Root string // Go root or Go path dir containing this package
|
||||
|
||||
// Source files
|
||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string // .go sources files that import "C"
|
||||
IgnoredGoFiles []string // .go sources ignored due to build constraints
|
||||
CFiles []string // .c source files
|
||||
CXXFiles []string // .cc, .cxx and .cpp source files
|
||||
MFiles []string // .m source files
|
||||
HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||
SFiles []string // .s source files
|
||||
SwigFiles []string // .swig files
|
||||
SwigCXXFiles []string // .swigcxx files
|
||||
SysoFiles []string // .syso object files to add to archive
|
||||
|
||||
// Cgo directives
|
||||
CgoCFLAGS []string // cgo: flags for C compiler
|
||||
CgoCPPFLAGS []string // cgo: flags for C preprocessor
|
||||
CgoCXXFLAGS []string // cgo: flags for C++ compiler
|
||||
CgoLDFLAGS []string // cgo: flags for linker
|
||||
CgoPkgConfig []string // cgo: pkg-config names
|
||||
|
||||
// Dependency information
|
||||
Imports []string // import paths used by this package
|
||||
Deps []string // all (recursively) imported dependencies
|
||||
|
||||
// Error information
|
||||
Incomplete bool // this package or a dependency has an error
|
||||
Error *PackageError // error loading package
|
||||
DepsErrors []*PackageError // errors loading dependencies
|
||||
|
||||
TestGoFiles []string // _test.go files in package
|
||||
TestImports []string // imports from TestGoFiles
|
||||
XTestGoFiles []string // _test.go files outside package
|
||||
XTestImports []string // imports from XTestGoFiles
|
||||
}
|
||||
|
||||
The template function "join" calls strings.Join.
|
||||
|
||||
The template function "context" returns the build context, defined as:
|
||||
|
||||
type Context struct {
|
||||
GOARCH string // target architecture
|
||||
GOOS string // target operating system
|
||||
GOROOT string // Go root
|
||||
GOPATH string // Go path
|
||||
CgoEnabled bool // whether cgo can be used
|
||||
UseAllFiles bool // use files regardless of +build lines, file names
|
||||
Compiler string // compiler to assume when computing target paths
|
||||
BuildTags []string // build constraints to match in +build lines
|
||||
ReleaseTags []string // releases the current release is compatible with
|
||||
InstallSuffix string // suffix to use in the name of the install dir
|
||||
}
|
||||
|
||||
For more information about the meaning of these fields see the documentation
|
||||
for the go/build package's Context type.
|
||||
|
||||
The -json flag causes the package data to be printed in JSON format
|
||||
instead of using the template format.
|
||||
|
||||
The -e flag changes the handling of erroneous packages, those that
|
||||
cannot be found or are malformed. By default, the list command
|
||||
prints an error to standard error for each erroneous package and
|
||||
omits the packages from consideration during the usual printing.
|
||||
With the -e flag, the list command never prints errors to standard
|
||||
error and instead processes the erroneous packages with the usual
|
||||
printing. Erroneous packages will have a non-empty ImportPath and
|
||||
a non-nil Error field; other information may or may not be missing
|
||||
(zeroed).
|
||||
|
||||
For more about build flags, see 'go help build'.
|
||||
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
`,
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmdList.Run = runList // break init cycle
|
||||
addBuildFlags(cmdList)
|
||||
}
|
||||
|
||||
var listE = cmdList.Flag.Bool("e", false, "")
|
||||
var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
|
||||
var listJson = cmdList.Flag.Bool("json", false, "")
|
||||
var nl = []byte{'\n'}
|
||||
|
||||
func runList(cmd *Command, args []string) {
|
||||
out := newTrackingWriter(os.Stdout)
|
||||
defer out.w.Flush()
|
||||
|
||||
var do func(*Package)
|
||||
if *listJson {
|
||||
do = func(p *Package) {
|
||||
b, err := json.MarshalIndent(p, "", "\t")
|
||||
if err != nil {
|
||||
out.Flush()
|
||||
fatalf("%s", err)
|
||||
}
|
||||
out.Write(b)
|
||||
out.Write(nl)
|
||||
}
|
||||
} else {
|
||||
var cachedCtxt *Context
|
||||
context := func() *Context {
|
||||
if cachedCtxt == nil {
|
||||
cachedCtxt = newContext(&buildContext)
|
||||
}
|
||||
return cachedCtxt
|
||||
}
|
||||
fm := template.FuncMap{
|
||||
"join": strings.Join,
|
||||
"context": context,
|
||||
}
|
||||
tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
|
||||
if err != nil {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
do = func(p *Package) {
|
||||
if err := tmpl.Execute(out, p); err != nil {
|
||||
out.Flush()
|
||||
fatalf("%s", err)
|
||||
}
|
||||
if out.NeedNL() {
|
||||
out.Write(nl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
load := packages
|
||||
if *listE {
|
||||
load = packagesAndErrors
|
||||
}
|
||||
|
||||
for _, pkg := range load(args) {
|
||||
do(pkg)
|
||||
}
|
||||
}
|
||||
|
||||
// TrackingWriter tracks the last byte written on every write so
|
||||
// we can avoid printing a newline if one was already written or
|
||||
// if there is no output at all.
|
||||
type TrackingWriter struct {
|
||||
w *bufio.Writer
|
||||
last byte
|
||||
}
|
||||
|
||||
func newTrackingWriter(w io.Writer) *TrackingWriter {
|
||||
return &TrackingWriter{
|
||||
w: bufio.NewWriter(w),
|
||||
last: '\n',
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TrackingWriter) Write(p []byte) (n int, err error) {
|
||||
n, err = t.w.Write(p)
|
||||
if n > 0 {
|
||||
t.last = p[n-1]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (t *TrackingWriter) Flush() {
|
||||
t.w.Flush()
|
||||
}
|
||||
|
||||
func (t *TrackingWriter) NeedNL() bool {
|
||||
return t.last != '\n'
|
||||
}
|
722
libgo/go/cmd/go/main.go
Normal file
722
libgo/go/cmd/go/main.go
Normal file
@ -0,0 +1,722 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// A Command is an implementation of a go command
|
||||
// like go build or go fix.
|
||||
type Command struct {
|
||||
// Run runs the command.
|
||||
// The args are the arguments after the command name.
|
||||
Run func(cmd *Command, args []string)
|
||||
|
||||
// UsageLine is the one-line usage message.
|
||||
// The first word in the line is taken to be the command name.
|
||||
UsageLine string
|
||||
|
||||
// Short is the short description shown in the 'go help' output.
|
||||
Short string
|
||||
|
||||
// Long is the long message shown in the 'go help <this-command>' output.
|
||||
Long string
|
||||
|
||||
// Flag is a set of flags specific to this command.
|
||||
Flag flag.FlagSet
|
||||
|
||||
// CustomFlags indicates that the command will do its own
|
||||
// flag parsing.
|
||||
CustomFlags bool
|
||||
}
|
||||
|
||||
// Name returns the command's name: the first word in the usage line.
|
||||
func (c *Command) Name() string {
|
||||
name := c.UsageLine
|
||||
i := strings.Index(name, " ")
|
||||
if i >= 0 {
|
||||
name = name[:i]
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func (c *Command) Usage() {
|
||||
fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
|
||||
fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
// Runnable reports whether the command can be run; otherwise
|
||||
// it is a documentation pseudo-command such as importpath.
|
||||
func (c *Command) Runnable() bool {
|
||||
return c.Run != nil
|
||||
}
|
||||
|
||||
// Commands lists the available commands and help topics.
|
||||
// The order here is the order in which they are printed by 'go help'.
|
||||
var commands = []*Command{
|
||||
cmdBuild,
|
||||
cmdClean,
|
||||
cmdEnv,
|
||||
cmdFix,
|
||||
cmdFmt,
|
||||
cmdGet,
|
||||
cmdInstall,
|
||||
cmdList,
|
||||
cmdRun,
|
||||
cmdTest,
|
||||
cmdTool,
|
||||
cmdVersion,
|
||||
cmdVet,
|
||||
|
||||
helpC,
|
||||
helpFileType,
|
||||
helpGopath,
|
||||
helpImportPath,
|
||||
helpPackages,
|
||||
helpTestflag,
|
||||
helpTestfunc,
|
||||
}
|
||||
|
||||
var exitStatus = 0
|
||||
var exitMu sync.Mutex
|
||||
|
||||
func setExitStatus(n int) {
|
||||
exitMu.Lock()
|
||||
if exitStatus < n {
|
||||
exitStatus = n
|
||||
}
|
||||
exitMu.Unlock()
|
||||
}
|
||||
|
||||
func main() {
|
||||
_ = go11tag
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
log.SetFlags(0)
|
||||
|
||||
args := flag.Args()
|
||||
if len(args) < 1 {
|
||||
usage()
|
||||
}
|
||||
|
||||
if args[0] == "help" {
|
||||
help(args[1:])
|
||||
return
|
||||
}
|
||||
|
||||
// Diagnose common mistake: GOPATH==GOROOT.
|
||||
// This setting is equivalent to not setting GOPATH at all,
|
||||
// which is not what most people want when they do it.
|
||||
if gopath := os.Getenv("GOPATH"); gopath == runtime.GOROOT() {
|
||||
fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
|
||||
} else {
|
||||
for _, p := range filepath.SplitList(gopath) {
|
||||
// Note: using HasPrefix instead of Contains because a ~ can appear
|
||||
// in the middle of directory elements, such as /tmp/git-1.8.2~rc3
|
||||
// or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell.
|
||||
if strings.HasPrefix(p, "~") {
|
||||
fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p)
|
||||
os.Exit(2)
|
||||
}
|
||||
if build.IsLocalImport(p) {
|
||||
fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nRun 'go help gopath' for usage.\n", p)
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if fi, err := os.Stat(goroot); err != nil || !fi.IsDir() {
|
||||
fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", goroot)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
for _, cmd := range commands {
|
||||
if cmd.Name() == args[0] && cmd.Run != nil {
|
||||
cmd.Flag.Usage = func() { cmd.Usage() }
|
||||
if cmd.CustomFlags {
|
||||
args = args[1:]
|
||||
} else {
|
||||
cmd.Flag.Parse(args[1:])
|
||||
args = cmd.Flag.Args()
|
||||
}
|
||||
cmd.Run(cmd, args)
|
||||
exit()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0])
|
||||
setExitStatus(2)
|
||||
exit()
|
||||
}
|
||||
|
||||
var usageTemplate = `Go is a tool for managing Go source code.
|
||||
|
||||
Usage:
|
||||
|
||||
go command [arguments]
|
||||
|
||||
The commands are:
|
||||
{{range .}}{{if .Runnable}}
|
||||
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
|
||||
|
||||
Use "go help [command]" for more information about a command.
|
||||
|
||||
Additional help topics:
|
||||
{{range .}}{{if not .Runnable}}
|
||||
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
|
||||
|
||||
Use "go help [topic]" for more information about that topic.
|
||||
|
||||
`
|
||||
|
||||
var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
|
||||
|
||||
{{end}}{{.Long | trim}}
|
||||
`
|
||||
|
||||
var documentationTemplate = `// 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.
|
||||
|
||||
// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
|
||||
// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
|
||||
|
||||
/*
|
||||
{{range .}}{{if .Short}}{{.Short | capitalize}}
|
||||
|
||||
{{end}}{{if .Runnable}}Usage:
|
||||
|
||||
go {{.UsageLine}}
|
||||
|
||||
{{end}}{{.Long | trim}}
|
||||
|
||||
|
||||
{{end}}*/
|
||||
package main
|
||||
`
|
||||
|
||||
// tmpl executes the given template text on data, writing the result to w.
|
||||
func tmpl(w io.Writer, text string, data interface{}) {
|
||||
t := template.New("top")
|
||||
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
|
||||
template.Must(t.Parse(text))
|
||||
if err := t.Execute(w, data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func capitalize(s string) string {
|
||||
if s == "" {
|
||||
return s
|
||||
}
|
||||
r, n := utf8.DecodeRuneInString(s)
|
||||
return string(unicode.ToTitle(r)) + s[n:]
|
||||
}
|
||||
|
||||
func printUsage(w io.Writer) {
|
||||
tmpl(w, usageTemplate, commands)
|
||||
}
|
||||
|
||||
func usage() {
|
||||
// special case "go test -h"
|
||||
if len(os.Args) > 1 && os.Args[1] == "test" {
|
||||
help([]string{"testflag"})
|
||||
os.Exit(2)
|
||||
}
|
||||
printUsage(os.Stderr)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
// help implements the 'help' command.
|
||||
func help(args []string) {
|
||||
if len(args) == 0 {
|
||||
printUsage(os.Stdout)
|
||||
// not exit 2: succeeded at 'go help'.
|
||||
return
|
||||
}
|
||||
if len(args) != 1 {
|
||||
fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
|
||||
os.Exit(2) // failed at 'go help'
|
||||
}
|
||||
|
||||
arg := args[0]
|
||||
|
||||
// 'go help documentation' generates doc.go.
|
||||
if arg == "documentation" {
|
||||
buf := new(bytes.Buffer)
|
||||
printUsage(buf)
|
||||
usage := &Command{Long: buf.String()}
|
||||
tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...))
|
||||
return
|
||||
}
|
||||
|
||||
for _, cmd := range commands {
|
||||
if cmd.Name() == arg {
|
||||
tmpl(os.Stdout, helpTemplate, cmd)
|
||||
// not exit 2: succeeded at 'go help cmd'.
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg)
|
||||
os.Exit(2) // failed at 'go help cmd'
|
||||
}
|
||||
|
||||
// importPathsNoDotExpansion returns the import paths to use for the given
|
||||
// command line, but it does no ... expansion.
|
||||
func importPathsNoDotExpansion(args []string) []string {
|
||||
if len(args) == 0 {
|
||||
return []string{"."}
|
||||
}
|
||||
var out []string
|
||||
for _, a := range args {
|
||||
// Arguments are supposed to be import paths, but
|
||||
// as a courtesy to Windows developers, rewrite \ to /
|
||||
// in command-line arguments. Handles .\... and so on.
|
||||
if filepath.Separator == '\\' {
|
||||
a = strings.Replace(a, `\`, `/`, -1)
|
||||
}
|
||||
|
||||
// Put argument in canonical form, but preserve leading ./.
|
||||
if strings.HasPrefix(a, "./") {
|
||||
a = "./" + path.Clean(a)
|
||||
if a == "./." {
|
||||
a = "."
|
||||
}
|
||||
} else {
|
||||
a = path.Clean(a)
|
||||
}
|
||||
if a == "all" || a == "std" {
|
||||
out = append(out, allPackages(a)...)
|
||||
continue
|
||||
}
|
||||
out = append(out, a)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// importPaths returns the import paths to use for the given command line.
|
||||
func importPaths(args []string) []string {
|
||||
args = importPathsNoDotExpansion(args)
|
||||
var out []string
|
||||
for _, a := range args {
|
||||
if strings.Contains(a, "...") {
|
||||
if build.IsLocalImport(a) {
|
||||
out = append(out, allPackagesInFS(a)...)
|
||||
} else {
|
||||
out = append(out, allPackages(a)...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
out = append(out, a)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
var atexitFuncs []func()
|
||||
|
||||
func atexit(f func()) {
|
||||
atexitFuncs = append(atexitFuncs, f)
|
||||
}
|
||||
|
||||
func exit() {
|
||||
for _, f := range atexitFuncs {
|
||||
f()
|
||||
}
|
||||
os.Exit(exitStatus)
|
||||
}
|
||||
|
||||
func fatalf(format string, args ...interface{}) {
|
||||
errorf(format, args...)
|
||||
exit()
|
||||
}
|
||||
|
||||
func errorf(format string, args ...interface{}) {
|
||||
log.Printf(format, args...)
|
||||
setExitStatus(1)
|
||||
}
|
||||
|
||||
var logf = log.Printf
|
||||
|
||||
func exitIfErrors() {
|
||||
if exitStatus != 0 {
|
||||
exit()
|
||||
}
|
||||
}
|
||||
|
||||
func run(cmdargs ...interface{}) {
|
||||
cmdline := stringList(cmdargs...)
|
||||
if buildN || buildX {
|
||||
fmt.Printf("%s\n", strings.Join(cmdline, " "))
|
||||
if buildN {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command(cmdline[0], cmdline[1:]...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
errorf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func runOut(dir string, cmdargs ...interface{}) []byte {
|
||||
cmdline := stringList(cmdargs...)
|
||||
cmd := exec.Command(cmdline[0], cmdline[1:]...)
|
||||
cmd.Dir = dir
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
os.Stderr.Write(out)
|
||||
errorf("%v", err)
|
||||
out = nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// envForDir returns a copy of the environment
|
||||
// suitable for running in the given directory.
|
||||
// The environment is the current process's environment
|
||||
// but with an updated $PWD, so that an os.Getwd in the
|
||||
// child will be faster.
|
||||
func envForDir(dir string) []string {
|
||||
env := os.Environ()
|
||||
// Internally we only use rooted paths, so dir is rooted.
|
||||
// Even if dir is not rooted, no harm done.
|
||||
return mergeEnvLists([]string{"PWD=" + dir}, env)
|
||||
}
|
||||
|
||||
// mergeEnvLists merges the two environment lists such that
|
||||
// variables with the same name in "in" replace those in "out".
|
||||
func mergeEnvLists(in, out []string) []string {
|
||||
NextVar:
|
||||
for _, inkv := range in {
|
||||
k := strings.SplitAfterN(inkv, "=", 2)[0]
|
||||
for i, outkv := range out {
|
||||
if strings.HasPrefix(outkv, k) {
|
||||
out[i] = inkv
|
||||
continue NextVar
|
||||
}
|
||||
}
|
||||
out = append(out, inkv)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// matchPattern(pattern)(name) reports whether
|
||||
// name matches pattern. Pattern is a limited glob
|
||||
// pattern in which '...' means 'any string' and there
|
||||
// is no other special syntax.
|
||||
func matchPattern(pattern string) func(name string) bool {
|
||||
re := regexp.QuoteMeta(pattern)
|
||||
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
|
||||
// Special case: foo/... matches foo too.
|
||||
if strings.HasSuffix(re, `/.*`) {
|
||||
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
|
||||
}
|
||||
reg := regexp.MustCompile(`^` + re + `$`)
|
||||
return func(name string) bool {
|
||||
return reg.MatchString(name)
|
||||
}
|
||||
}
|
||||
|
||||
// hasPathPrefix reports whether the path s begins with the
|
||||
// elements in prefix.
|
||||
func hasPathPrefix(s, prefix string) bool {
|
||||
switch {
|
||||
default:
|
||||
return false
|
||||
case len(s) == len(prefix):
|
||||
return s == prefix
|
||||
case len(s) > len(prefix):
|
||||
if prefix != "" && prefix[len(prefix)-1] == '/' {
|
||||
return strings.HasPrefix(s, prefix)
|
||||
}
|
||||
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
|
||||
}
|
||||
}
|
||||
|
||||
// treeCanMatchPattern(pattern)(name) reports whether
|
||||
// name or children of name can possibly match pattern.
|
||||
// Pattern is the same limited glob accepted by matchPattern.
|
||||
func treeCanMatchPattern(pattern string) func(name string) bool {
|
||||
wildCard := false
|
||||
if i := strings.Index(pattern, "..."); i >= 0 {
|
||||
wildCard = true
|
||||
pattern = pattern[:i]
|
||||
}
|
||||
return func(name string) bool {
|
||||
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
|
||||
wildCard && strings.HasPrefix(name, pattern)
|
||||
}
|
||||
}
|
||||
|
||||
// allPackages returns all the packages that can be found
|
||||
// under the $GOPATH directories and $GOROOT matching pattern.
|
||||
// The pattern is either "all" (all packages), "std" (standard packages)
|
||||
// or a path including "...".
|
||||
func allPackages(pattern string) []string {
|
||||
pkgs := matchPackages(pattern)
|
||||
if len(pkgs) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func matchPackages(pattern string) []string {
|
||||
match := func(string) bool { return true }
|
||||
treeCanMatch := func(string) bool { return true }
|
||||
if pattern != "all" && pattern != "std" {
|
||||
match = matchPattern(pattern)
|
||||
treeCanMatch = treeCanMatchPattern(pattern)
|
||||
}
|
||||
|
||||
have := map[string]bool{
|
||||
"builtin": true, // ignore pseudo-package that exists only for documentation
|
||||
}
|
||||
if !buildContext.CgoEnabled {
|
||||
have["runtime/cgo"] = true // ignore during walk
|
||||
}
|
||||
var pkgs []string
|
||||
|
||||
// Commands
|
||||
cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
|
||||
filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil || !fi.IsDir() || path == cmd {
|
||||
return nil
|
||||
}
|
||||
name := path[len(cmd):]
|
||||
if !treeCanMatch(name) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
// Commands are all in cmd/, not in subdirectories.
|
||||
if strings.Contains(name, string(filepath.Separator)) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
// We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
|
||||
name = "cmd/" + name
|
||||
if have[name] {
|
||||
return nil
|
||||
}
|
||||
have[name] = true
|
||||
if !match(name) {
|
||||
return nil
|
||||
}
|
||||
_, err = buildContext.ImportDir(path, 0)
|
||||
if err != nil {
|
||||
if _, noGo := err.(*build.NoGoError); !noGo {
|
||||
log.Print(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
pkgs = append(pkgs, name)
|
||||
return nil
|
||||
})
|
||||
|
||||
for _, src := range buildContext.SrcDirs() {
|
||||
if pattern == "std" && src != gorootSrcPkg {
|
||||
continue
|
||||
}
|
||||
src = filepath.Clean(src) + string(filepath.Separator)
|
||||
filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil || !fi.IsDir() || path == src {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Avoid .foo, _foo, and testdata directory trees.
|
||||
_, elem := filepath.Split(path)
|
||||
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
name := filepath.ToSlash(path[len(src):])
|
||||
if pattern == "std" && strings.Contains(name, ".") {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if !treeCanMatch(name) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if have[name] {
|
||||
return nil
|
||||
}
|
||||
have[name] = true
|
||||
if !match(name) {
|
||||
return nil
|
||||
}
|
||||
_, err = buildContext.ImportDir(path, 0)
|
||||
if err != nil {
|
||||
if _, noGo := err.(*build.NoGoError); noGo {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
pkgs = append(pkgs, name)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
||||
// allPackagesInFS is like allPackages but is passed a pattern
|
||||
// beginning ./ or ../, meaning it should scan the tree rooted
|
||||
// at the given directory. There are ... in the pattern too.
|
||||
func allPackagesInFS(pattern string) []string {
|
||||
pkgs := matchPackagesInFS(pattern)
|
||||
if len(pkgs) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func matchPackagesInFS(pattern string) []string {
|
||||
// Find directory to begin the scan.
|
||||
// Could be smarter but this one optimization
|
||||
// is enough for now, since ... is usually at the
|
||||
// end of a path.
|
||||
i := strings.Index(pattern, "...")
|
||||
dir, _ := path.Split(pattern[:i])
|
||||
|
||||
// pattern begins with ./ or ../.
|
||||
// path.Clean will discard the ./ but not the ../.
|
||||
// We need to preserve the ./ for pattern matching
|
||||
// and in the returned import paths.
|
||||
prefix := ""
|
||||
if strings.HasPrefix(pattern, "./") {
|
||||
prefix = "./"
|
||||
}
|
||||
match := matchPattern(pattern)
|
||||
|
||||
var pkgs []string
|
||||
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil || !fi.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if path == dir {
|
||||
// filepath.Walk starts at dir and recurses. For the recursive case,
|
||||
// the path is the result of filepath.Join, which calls filepath.Clean.
|
||||
// The initial case is not Cleaned, though, so we do this explicitly.
|
||||
//
|
||||
// This converts a path like "./io/" to "io". Without this step, running
|
||||
// "cd $GOROOT/src/pkg; go list ./io/..." would incorrectly skip the io
|
||||
// package, because prepending the prefix "./" to the unclean path would
|
||||
// result in "././io", and match("././io") returns false.
|
||||
path = filepath.Clean(path)
|
||||
}
|
||||
|
||||
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
|
||||
_, elem := filepath.Split(path)
|
||||
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
|
||||
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
name := prefix + filepath.ToSlash(path)
|
||||
if !match(name) {
|
||||
return nil
|
||||
}
|
||||
if _, err = build.ImportDir(path, 0); err != nil {
|
||||
if _, noGo := err.(*build.NoGoError); !noGo {
|
||||
log.Print(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
pkgs = append(pkgs, name)
|
||||
return nil
|
||||
})
|
||||
return pkgs
|
||||
}
|
||||
|
||||
// stringList's arguments should be a sequence of string or []string values.
|
||||
// stringList flattens them into a single []string.
|
||||
func stringList(args ...interface{}) []string {
|
||||
var x []string
|
||||
for _, arg := range args {
|
||||
switch arg := arg.(type) {
|
||||
case []string:
|
||||
x = append(x, arg...)
|
||||
case string:
|
||||
x = append(x, arg)
|
||||
default:
|
||||
panic("stringList: invalid argument")
|
||||
}
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// toFold returns a string with the property that
|
||||
// strings.EqualFold(s, t) iff toFold(s) == toFold(t)
|
||||
// This lets us test a large set of strings for fold-equivalent
|
||||
// duplicates without making a quadratic number of calls
|
||||
// to EqualFold. Note that strings.ToUpper and strings.ToLower
|
||||
// have the desired property in some corner cases.
|
||||
func toFold(s string) string {
|
||||
// Fast path: all ASCII, no upper case.
|
||||
// Most paths look like this already.
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
|
||||
goto Slow
|
||||
}
|
||||
}
|
||||
return s
|
||||
|
||||
Slow:
|
||||
var buf bytes.Buffer
|
||||
for _, r := range s {
|
||||
// SimpleFold(x) cycles to the next equivalent rune > x
|
||||
// or wraps around to smaller values. Iterate until it wraps,
|
||||
// and we've found the minimum value.
|
||||
for {
|
||||
r0 := r
|
||||
r = unicode.SimpleFold(r0)
|
||||
if r <= r0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Exception to allow fast path above: A-Z => a-z
|
||||
if 'A' <= r && r <= 'Z' {
|
||||
r += 'a' - 'A'
|
||||
}
|
||||
buf.WriteRune(r)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// foldDup reports a pair of strings from the list that are
|
||||
// equal according to strings.EqualFold.
|
||||
// It returns "", "" if there are no such strings.
|
||||
func foldDup(list []string) (string, string) {
|
||||
clash := map[string]string{}
|
||||
for _, s := range list {
|
||||
fold := toFold(s)
|
||||
if t := clash[fold]; t != "" {
|
||||
if s > t {
|
||||
s, t = t, s
|
||||
}
|
||||
return s, t
|
||||
}
|
||||
clash[fold] = s
|
||||
}
|
||||
return "", ""
|
||||
}
|
88
libgo/go/cmd/go/match_test.go
Normal file
88
libgo/go/cmd/go/match_test.go
Normal file
@ -0,0 +1,88 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
var matchPatternTests = []stringPairTest{
|
||||
{"...", "foo", true},
|
||||
{"net", "net", true},
|
||||
{"net", "net/http", false},
|
||||
{"net/http", "net", false},
|
||||
{"net/http", "net/http", true},
|
||||
{"net...", "netchan", true},
|
||||
{"net...", "net", true},
|
||||
{"net...", "net/http", true},
|
||||
{"net...", "not/http", false},
|
||||
{"net/...", "netchan", false},
|
||||
{"net/...", "net", true},
|
||||
{"net/...", "net/http", true},
|
||||
{"net/...", "not/http", false},
|
||||
}
|
||||
|
||||
func TestMatchPattern(t *testing.T) {
|
||||
testStringPairs(t, "matchPattern", matchPatternTests, func(pattern, name string) bool {
|
||||
return matchPattern(pattern)(name)
|
||||
})
|
||||
}
|
||||
|
||||
var treeCanMatchPatternTests = []stringPairTest{
|
||||
{"...", "foo", true},
|
||||
{"net", "net", true},
|
||||
{"net", "net/http", false},
|
||||
{"net/http", "net", true},
|
||||
{"net/http", "net/http", true},
|
||||
{"net...", "netchan", true},
|
||||
{"net...", "net", true},
|
||||
{"net...", "net/http", true},
|
||||
{"net...", "not/http", false},
|
||||
{"net/...", "netchan", false},
|
||||
{"net/...", "net", true},
|
||||
{"net/...", "net/http", true},
|
||||
{"net/...", "not/http", false},
|
||||
{"abc.../def", "abcxyz", true},
|
||||
{"abc.../def", "xyxabc", false},
|
||||
{"x/y/z/...", "x", true},
|
||||
{"x/y/z/...", "x/y", true},
|
||||
{"x/y/z/...", "x/y/z", true},
|
||||
{"x/y/z/...", "x/y/z/w", true},
|
||||
{"x/y/z", "x", true},
|
||||
{"x/y/z", "x/y", true},
|
||||
{"x/y/z", "x/y/z", true},
|
||||
{"x/y/z", "x/y/z/w", false},
|
||||
{"x/.../y/z", "x/a/b/c", true},
|
||||
{"x/.../y/z", "y/x/a/b/c", false},
|
||||
}
|
||||
|
||||
func TestChildrenCanMatchPattern(t *testing.T) {
|
||||
testStringPairs(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool {
|
||||
return treeCanMatchPattern(pattern)(name)
|
||||
})
|
||||
}
|
||||
|
||||
var hasPathPrefixTests = []stringPairTest{
|
||||
{"abc", "a", false},
|
||||
{"a/bc", "a", true},
|
||||
{"a", "a", true},
|
||||
{"a/bc", "a/", true},
|
||||
}
|
||||
|
||||
func TestHasPathPrefix(t *testing.T) {
|
||||
testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix)
|
||||
}
|
||||
|
||||
type stringPairTest struct {
|
||||
in1 string
|
||||
in2 string
|
||||
out bool
|
||||
}
|
||||
|
||||
func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) {
|
||||
for _, tt := range tests {
|
||||
if out := f(tt.in1, tt.in2); out != tt.out {
|
||||
t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
9
libgo/go/cmd/go/mkdoc.sh
Normal file
9
libgo/go/cmd/go/mkdoc.sh
Normal file
@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
# 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.
|
||||
|
||||
go install # So the next line will produce updated documentation.
|
||||
go help documentation > doc.go
|
||||
gofmt -w doc.go
|
||||
|
856
libgo/go/cmd/go/pkg.go
Normal file
856
libgo/go/cmd/go/pkg.go
Normal file
@ -0,0 +1,856 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"os"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// A Package describes a single package found in a directory.
|
||||
type Package struct {
|
||||
// Note: These fields are part of the go command's public API.
|
||||
// See list.go. It is okay to add fields, but not to change or
|
||||
// remove existing ones. Keep in sync with list.go
|
||||
Dir string `json:",omitempty"` // directory containing package sources
|
||||
ImportPath string `json:",omitempty"` // import path of package in dir
|
||||
Name string `json:",omitempty"` // package name
|
||||
Doc string `json:",omitempty"` // package documentation string
|
||||
Target string `json:",omitempty"` // install path
|
||||
Goroot bool `json:",omitempty"` // is this package found in the Go root?
|
||||
Standard bool `json:",omitempty"` // is this package part of the standard Go library?
|
||||
Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
|
||||
Root string `json:",omitempty"` // Go root or Go path dir containing this package
|
||||
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
|
||||
|
||||
// Source files
|
||||
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
|
||||
IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
|
||||
CFiles []string `json:",omitempty"` // .c source files
|
||||
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
|
||||
MFiles []string `json:",omitempty"` // .m source files
|
||||
HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
|
||||
SFiles []string `json:",omitempty"` // .s source files
|
||||
SwigFiles []string `json:",omitempty"` // .swig files
|
||||
SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
|
||||
SysoFiles []string `json:",omitempty"` // .syso system object files added to package
|
||||
|
||||
// Cgo directives
|
||||
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
|
||||
CgoCPPFLAGS []string `json:",omitempty"` // cgo: flags for C preprocessor
|
||||
CgoCXXFLAGS []string `json:",omitempty"` // cgo: flags for C++ compiler
|
||||
CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker
|
||||
CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
|
||||
|
||||
// Dependency information
|
||||
Imports []string `json:",omitempty"` // import paths used by this package
|
||||
Deps []string `json:",omitempty"` // all (recursively) imported dependencies
|
||||
|
||||
// Error information
|
||||
Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
|
||||
Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
|
||||
DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
|
||||
|
||||
// Test information
|
||||
TestGoFiles []string `json:",omitempty"` // _test.go files in package
|
||||
TestImports []string `json:",omitempty"` // imports from TestGoFiles
|
||||
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
|
||||
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
|
||||
|
||||
// Unexported fields are not part of the public API.
|
||||
build *build.Package
|
||||
pkgdir string // overrides build.PkgDir
|
||||
imports []*Package
|
||||
deps []*Package
|
||||
gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
|
||||
sfiles []string
|
||||
allgofiles []string // gofiles + IgnoredGoFiles, absolute paths
|
||||
target string // installed file for this package (may be executable)
|
||||
fake bool // synthesized package
|
||||
forceBuild bool // this package must be rebuilt
|
||||
forceLibrary bool // this package is a library (even if named "main")
|
||||
cmdline bool // defined by files listed on command line
|
||||
local bool // imported via local path (./ or ../)
|
||||
localPrefix string // interpret ./ and ../ imports relative to this prefix
|
||||
exeName string // desired name for temporary executable
|
||||
coverMode string // preprocess Go source files with the coverage tool in this mode
|
||||
coverVars map[string]*CoverVar // variables created by coverage analysis
|
||||
omitDWARF bool // tell linker not to write DWARF information
|
||||
}
|
||||
|
||||
// CoverVar holds the name of the generated coverage variables targeting the named file.
|
||||
type CoverVar struct {
|
||||
File string // local file name
|
||||
Var string // name of count struct
|
||||
}
|
||||
|
||||
func (p *Package) copyBuild(pp *build.Package) {
|
||||
p.build = pp
|
||||
|
||||
p.Dir = pp.Dir
|
||||
p.ImportPath = pp.ImportPath
|
||||
p.Name = pp.Name
|
||||
p.Doc = pp.Doc
|
||||
p.Root = pp.Root
|
||||
p.ConflictDir = pp.ConflictDir
|
||||
// TODO? Target
|
||||
p.Goroot = pp.Goroot
|
||||
p.Standard = p.Goroot && p.ImportPath != "" && !strings.Contains(p.ImportPath, ".")
|
||||
p.GoFiles = pp.GoFiles
|
||||
p.CgoFiles = pp.CgoFiles
|
||||
p.IgnoredGoFiles = pp.IgnoredGoFiles
|
||||
p.CFiles = pp.CFiles
|
||||
p.CXXFiles = pp.CXXFiles
|
||||
p.MFiles = pp.MFiles
|
||||
p.HFiles = pp.HFiles
|
||||
p.SFiles = pp.SFiles
|
||||
p.SwigFiles = pp.SwigFiles
|
||||
p.SwigCXXFiles = pp.SwigCXXFiles
|
||||
p.SysoFiles = pp.SysoFiles
|
||||
p.CgoCFLAGS = pp.CgoCFLAGS
|
||||
p.CgoCPPFLAGS = pp.CgoCPPFLAGS
|
||||
p.CgoCXXFLAGS = pp.CgoCXXFLAGS
|
||||
p.CgoLDFLAGS = pp.CgoLDFLAGS
|
||||
p.CgoPkgConfig = pp.CgoPkgConfig
|
||||
p.Imports = pp.Imports
|
||||
p.TestGoFiles = pp.TestGoFiles
|
||||
p.TestImports = pp.TestImports
|
||||
p.XTestGoFiles = pp.XTestGoFiles
|
||||
p.XTestImports = pp.XTestImports
|
||||
}
|
||||
|
||||
// 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
|
||||
isImportCycle bool // the error is an import cycle
|
||||
hard bool // whether the error is soft or hard; soft errors are ignored in some places
|
||||
}
|
||||
|
||||
func (p *PackageError) Error() string {
|
||||
// Import cycles deserve special treatment.
|
||||
if p.isImportCycle {
|
||||
return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
|
||||
}
|
||||
if p.Pos != "" {
|
||||
// Omit import stack. The full path to the file where the error
|
||||
// is the most important thing.
|
||||
return p.Pos + ": " + p.Err
|
||||
}
|
||||
if len(p.ImportStack) == 0 {
|
||||
return p.Err
|
||||
}
|
||||
return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
|
||||
}
|
||||
|
||||
// An importStack is a stack of import paths.
|
||||
type importStack []string
|
||||
|
||||
func (s *importStack) push(p string) {
|
||||
*s = append(*s, p)
|
||||
}
|
||||
|
||||
func (s *importStack) pop() {
|
||||
*s = (*s)[0 : len(*s)-1]
|
||||
}
|
||||
|
||||
func (s *importStack) copy() []string {
|
||||
return append([]string{}, *s...)
|
||||
}
|
||||
|
||||
// shorterThan returns true if sp is shorter than t.
|
||||
// We use this to record the shortest import sequence
|
||||
// that leads to a particular package.
|
||||
func (sp *importStack) shorterThan(t []string) bool {
|
||||
s := *sp
|
||||
if len(s) != len(t) {
|
||||
return len(s) < len(t)
|
||||
}
|
||||
// If they are the same length, settle ties using string ordering.
|
||||
for i := range s {
|
||||
if s[i] != t[i] {
|
||||
return s[i] < t[i]
|
||||
}
|
||||
}
|
||||
return false // they are equal
|
||||
}
|
||||
|
||||
// packageCache is a lookup cache for loadPackage,
|
||||
// so that if we look up a package multiple times
|
||||
// we return the same pointer each time.
|
||||
var packageCache = map[string]*Package{}
|
||||
|
||||
// reloadPackage is like loadPackage but makes sure
|
||||
// not to use the package cache.
|
||||
func reloadPackage(arg string, stk *importStack) *Package {
|
||||
p := packageCache[arg]
|
||||
if p != nil {
|
||||
delete(packageCache, p.Dir)
|
||||
delete(packageCache, p.ImportPath)
|
||||
}
|
||||
return loadPackage(arg, stk)
|
||||
}
|
||||
|
||||
// dirToImportPath returns the pseudo-import path we use for a package
|
||||
// outside the Go path. It begins with _/ and then contains the full path
|
||||
// to the directory. If the package lives in c:\home\gopher\my\pkg then
|
||||
// the pseudo-import path is _/c_/home/gopher/my/pkg.
|
||||
// Using a pseudo-import path like this makes the ./ imports no longer
|
||||
// a special case, so that all the code to deal with ordinary imports works
|
||||
// automatically.
|
||||
func dirToImportPath(dir string) string {
|
||||
return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir)))
|
||||
}
|
||||
|
||||
func makeImportValid(r rune) rune {
|
||||
// Should match Go spec, compilers, and ../../pkg/go/parser/parser.go:/isValidImport.
|
||||
const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
|
||||
if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
|
||||
return '_'
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// loadImport scans the directory named by path, which must be an import path,
|
||||
// but possibly a local import path (an absolute file system path or one beginning
|
||||
// with ./ or ../). A local relative path is interpreted relative to srcDir.
|
||||
// It returns a *Package describing the package found in that directory.
|
||||
func loadImport(path string, srcDir string, stk *importStack, importPos []token.Position) *Package {
|
||||
stk.push(path)
|
||||
defer stk.pop()
|
||||
|
||||
// Determine canonical identifier for this package.
|
||||
// For a local import the identifier is the pseudo-import path
|
||||
// we create from the full directory to the package.
|
||||
// Otherwise it is the usual import path.
|
||||
importPath := path
|
||||
isLocal := build.IsLocalImport(path)
|
||||
if isLocal {
|
||||
importPath = dirToImportPath(filepath.Join(srcDir, path))
|
||||
}
|
||||
if p := packageCache[importPath]; p != nil {
|
||||
return reusePackage(p, stk)
|
||||
}
|
||||
|
||||
p := new(Package)
|
||||
p.local = isLocal
|
||||
p.ImportPath = importPath
|
||||
packageCache[importPath] = p
|
||||
|
||||
// Load package.
|
||||
// Import always returns bp != nil, even if an error occurs,
|
||||
// in order to return partial information.
|
||||
//
|
||||
// TODO: After Go 1, decide when to pass build.AllowBinary here.
|
||||
// See issue 3268 for mistakes to avoid.
|
||||
bp, err := buildContext.Import(path, srcDir, 0)
|
||||
bp.ImportPath = importPath
|
||||
if gobin != "" {
|
||||
bp.BinDir = gobin
|
||||
}
|
||||
p.load(stk, bp, err)
|
||||
if p.Error != nil && len(importPos) > 0 {
|
||||
pos := importPos[0]
|
||||
pos.Filename = shortPath(pos.Filename)
|
||||
p.Error.Pos = pos.String()
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// reusePackage reuses package p to satisfy the import at the top
|
||||
// of the import stack stk. If this use causes an import loop,
|
||||
// reusePackage updates p's error information to record the loop.
|
||||
func reusePackage(p *Package, stk *importStack) *Package {
|
||||
// We use p.imports==nil to detect a package that
|
||||
// is in the midst of its own loadPackage call
|
||||
// (all the recursion below happens before p.imports gets set).
|
||||
if p.imports == nil {
|
||||
if p.Error == nil {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.copy(),
|
||||
Err: "import cycle not allowed",
|
||||
isImportCycle: true,
|
||||
}
|
||||
}
|
||||
p.Incomplete = true
|
||||
}
|
||||
// Don't rewrite the import stack in the error if we have an import cycle.
|
||||
// If we do, we'll lose the path that describes the cycle.
|
||||
if p.Error != nil && !p.Error.isImportCycle && stk.shorterThan(p.Error.ImportStack) {
|
||||
p.Error.ImportStack = stk.copy()
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
type targetDir int
|
||||
|
||||
const (
|
||||
toRoot targetDir = iota // to bin dir inside package root (default)
|
||||
toTool // GOROOT/pkg/tool
|
||||
toBin // GOROOT/bin
|
||||
)
|
||||
|
||||
// goTools is a map of Go program import path to install target directory.
|
||||
var goTools = map[string]targetDir{
|
||||
"cmd/addr2line": toTool,
|
||||
"cmd/api": toTool,
|
||||
"cmd/cgo": toTool,
|
||||
"cmd/fix": toTool,
|
||||
"cmd/link": toTool,
|
||||
"cmd/nm": toTool,
|
||||
"cmd/objdump": toTool,
|
||||
"cmd/pack": toTool,
|
||||
"cmd/yacc": toTool,
|
||||
"code.google.com/p/go.tools/cmd/cover": toTool,
|
||||
"code.google.com/p/go.tools/cmd/godoc": toBin,
|
||||
"code.google.com/p/go.tools/cmd/vet": toTool,
|
||||
}
|
||||
|
||||
// expandScanner expands a scanner.List error into all the errors in the list.
|
||||
// The default Error method only shows the first error.
|
||||
func expandScanner(err error) error {
|
||||
// Look for parser errors.
|
||||
if err, ok := err.(scanner.ErrorList); ok {
|
||||
// Prepare error with \n before each message.
|
||||
// When printed in something like context: %v
|
||||
// this will put the leading file positions each on
|
||||
// its own line. It will also show all the errors
|
||||
// instead of just the first, as err.Error does.
|
||||
var buf bytes.Buffer
|
||||
for _, e := range err {
|
||||
e.Pos.Filename = shortPath(e.Pos.Filename)
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString(e.Error())
|
||||
}
|
||||
return errors.New(buf.String())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var raceExclude = map[string]bool{
|
||||
"runtime/race": true,
|
||||
"runtime/cgo": true,
|
||||
"cmd/cgo": true,
|
||||
"syscall": true,
|
||||
"errors": true,
|
||||
}
|
||||
|
||||
var cgoExclude = map[string]bool{
|
||||
"runtime/cgo": true,
|
||||
}
|
||||
|
||||
var cgoSyscallExclude = map[string]bool{
|
||||
"runtime/cgo": true,
|
||||
"runtime/race": true,
|
||||
}
|
||||
|
||||
// load populates p using information from bp, err, which should
|
||||
// be the result of calling build.Context.Import.
|
||||
func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package {
|
||||
p.copyBuild(bp)
|
||||
|
||||
// The localPrefix is the path we interpret ./ imports relative to.
|
||||
// Synthesized main packages sometimes override this.
|
||||
p.localPrefix = dirToImportPath(p.Dir)
|
||||
|
||||
if err != nil {
|
||||
p.Incomplete = true
|
||||
err = expandScanner(err)
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.copy(),
|
||||
Err: err.Error(),
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
if p.Name == "main" {
|
||||
_, elem := filepath.Split(p.Dir)
|
||||
full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
|
||||
if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {
|
||||
// Install cross-compiled binaries to subdirectories of bin.
|
||||
elem = full
|
||||
}
|
||||
if p.build.BinDir != gobin && goTools[p.ImportPath] == toBin {
|
||||
// Override BinDir.
|
||||
// This is from a subrepo but installs to $GOROOT/bin
|
||||
// by default anyway (like godoc).
|
||||
p.target = filepath.Join(gorootBin, elem)
|
||||
} else if p.build.BinDir != "" {
|
||||
// Install to GOBIN or bin of GOPATH entry.
|
||||
p.target = filepath.Join(p.build.BinDir, elem)
|
||||
}
|
||||
if goTools[p.ImportPath] == toTool {
|
||||
// This is for 'go tool'.
|
||||
// Override all the usual logic and force it into the tool directory.
|
||||
p.target = filepath.Join(gorootPkg, "tool", full)
|
||||
}
|
||||
if p.target != "" && buildContext.GOOS == "windows" {
|
||||
p.target += ".exe"
|
||||
}
|
||||
} else if p.local {
|
||||
// Local import turned into absolute path.
|
||||
// No permanent install target.
|
||||
p.target = ""
|
||||
} else {
|
||||
p.target = p.build.PkgObj
|
||||
}
|
||||
|
||||
importPaths := p.Imports
|
||||
// Packages that use cgo import runtime/cgo implicitly.
|
||||
// Packages that use cgo also import syscall implicitly,
|
||||
// to wrap errno.
|
||||
// Exclude certain packages to avoid circular dependencies.
|
||||
if len(p.CgoFiles) > 0 && (!p.Standard || !cgoExclude[p.ImportPath]) {
|
||||
importPaths = append(importPaths, "runtime/cgo")
|
||||
}
|
||||
if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
|
||||
importPaths = append(importPaths, "syscall")
|
||||
}
|
||||
// Everything depends on runtime, except runtime and unsafe.
|
||||
if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
|
||||
importPaths = append(importPaths, "runtime")
|
||||
// When race detection enabled everything depends on runtime/race.
|
||||
// Exclude certain packages to avoid circular dependencies.
|
||||
if buildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
|
||||
importPaths = append(importPaths, "runtime/race")
|
||||
}
|
||||
}
|
||||
|
||||
// Build list of full paths to all Go files in the package,
|
||||
// for use by commands like go fmt.
|
||||
p.gofiles = stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
|
||||
for i := range p.gofiles {
|
||||
p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i])
|
||||
}
|
||||
sort.Strings(p.gofiles)
|
||||
|
||||
p.sfiles = stringList(p.SFiles)
|
||||
for i := range p.sfiles {
|
||||
p.sfiles[i] = filepath.Join(p.Dir, p.sfiles[i])
|
||||
}
|
||||
sort.Strings(p.sfiles)
|
||||
|
||||
p.allgofiles = stringList(p.IgnoredGoFiles)
|
||||
for i := range p.allgofiles {
|
||||
p.allgofiles[i] = filepath.Join(p.Dir, p.allgofiles[i])
|
||||
}
|
||||
p.allgofiles = append(p.allgofiles, p.gofiles...)
|
||||
sort.Strings(p.allgofiles)
|
||||
|
||||
// Check for case-insensitive collision of input files.
|
||||
// To avoid problems on case-insensitive files, we reject any package
|
||||
// where two different input files have equal names under a case-insensitive
|
||||
// comparison.
|
||||
f1, f2 := foldDup(stringList(
|
||||
p.GoFiles,
|
||||
p.CgoFiles,
|
||||
p.IgnoredGoFiles,
|
||||
p.CFiles,
|
||||
p.CXXFiles,
|
||||
p.MFiles,
|
||||
p.HFiles,
|
||||
p.SFiles,
|
||||
p.SysoFiles,
|
||||
p.SwigFiles,
|
||||
p.SwigCXXFiles,
|
||||
p.TestGoFiles,
|
||||
p.XTestGoFiles,
|
||||
))
|
||||
if f1 != "" {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.copy(),
|
||||
Err: fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2),
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Build list of imported packages and full dependency list.
|
||||
imports := make([]*Package, 0, len(p.Imports))
|
||||
deps := make(map[string]bool)
|
||||
for i, path := range importPaths {
|
||||
if path == "C" {
|
||||
continue
|
||||
}
|
||||
p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])
|
||||
if !reqPkgSrc && p1.Root == "" {
|
||||
continue
|
||||
}
|
||||
if p1.local {
|
||||
if !p.local && p.Error == nil {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.copy(),
|
||||
Err: fmt.Sprintf("local import %q in non-local package", path),
|
||||
}
|
||||
pos := p.build.ImportPos[path]
|
||||
if len(pos) > 0 {
|
||||
p.Error.Pos = pos[0].String()
|
||||
}
|
||||
}
|
||||
path = p1.ImportPath
|
||||
importPaths[i] = path
|
||||
}
|
||||
deps[path] = true
|
||||
imports = append(imports, p1)
|
||||
for _, dep := range p1.Deps {
|
||||
deps[dep] = true
|
||||
}
|
||||
if p1.Incomplete {
|
||||
p.Incomplete = true
|
||||
}
|
||||
}
|
||||
p.imports = imports
|
||||
|
||||
p.Deps = make([]string, 0, len(deps))
|
||||
for dep := range deps {
|
||||
p.Deps = append(p.Deps, dep)
|
||||
}
|
||||
sort.Strings(p.Deps)
|
||||
for _, dep := range p.Deps {
|
||||
p1 := packageCache[dep]
|
||||
if p1 == nil {
|
||||
panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
|
||||
}
|
||||
p.deps = append(p.deps, p1)
|
||||
if p1.Error != nil {
|
||||
p.DepsErrors = append(p.DepsErrors, p1.Error)
|
||||
}
|
||||
}
|
||||
|
||||
// unsafe is a fake package.
|
||||
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
|
||||
p.target = ""
|
||||
}
|
||||
p.Target = p.target
|
||||
|
||||
// In the absence of errors lower in the dependency tree,
|
||||
// check for case-insensitive collisions of import paths.
|
||||
if len(p.DepsErrors) == 0 {
|
||||
dep1, dep2 := foldDup(p.Deps)
|
||||
if dep1 != "" {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.copy(),
|
||||
Err: fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2),
|
||||
}
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// usesSwig reports whether the package needs to run SWIG.
|
||||
func (p *Package) usesSwig() bool {
|
||||
return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
|
||||
}
|
||||
|
||||
// usesCgo reports whether the package needs to run cgo
|
||||
func (p *Package) usesCgo() bool {
|
||||
return len(p.CgoFiles) > 0
|
||||
}
|
||||
|
||||
// packageList returns the list of packages in the dag rooted at roots
|
||||
// as visited in a depth-first post-order traversal.
|
||||
func packageList(roots []*Package) []*Package {
|
||||
seen := map[*Package]bool{}
|
||||
all := []*Package{}
|
||||
var walk func(*Package)
|
||||
walk = func(p *Package) {
|
||||
if seen[p] {
|
||||
return
|
||||
}
|
||||
seen[p] = true
|
||||
for _, p1 := range p.imports {
|
||||
walk(p1)
|
||||
}
|
||||
all = append(all, p)
|
||||
}
|
||||
for _, root := range roots {
|
||||
walk(root)
|
||||
}
|
||||
return all
|
||||
}
|
||||
|
||||
// computeStale computes the Stale flag in the package dag that starts
|
||||
// at the named pkgs (command-line arguments).
|
||||
func computeStale(pkgs ...*Package) {
|
||||
topRoot := map[string]bool{}
|
||||
for _, p := range pkgs {
|
||||
topRoot[p.Root] = true
|
||||
}
|
||||
|
||||
for _, p := range packageList(pkgs) {
|
||||
p.Stale = isStale(p, topRoot)
|
||||
}
|
||||
}
|
||||
|
||||
// isStale reports whether package p needs to be rebuilt.
|
||||
func isStale(p *Package, topRoot map[string]bool) bool {
|
||||
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
|
||||
// fake, builtin package
|
||||
return false
|
||||
}
|
||||
if p.Error != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
// A package without Go sources means we only found
|
||||
// the installed .a file. Since we don't know how to rebuild
|
||||
// it, it can't be stale, even if -a is set. This enables binary-only
|
||||
// distributions of Go packages, although such binaries are
|
||||
// only useful with the specific version of the toolchain that
|
||||
// created them.
|
||||
if len(p.gofiles) == 0 && !p.usesSwig() {
|
||||
return false
|
||||
}
|
||||
|
||||
if buildA || p.target == "" || p.Stale {
|
||||
return true
|
||||
}
|
||||
|
||||
// Package is stale if completely unbuilt.
|
||||
var built time.Time
|
||||
if fi, err := os.Stat(p.target); err == nil {
|
||||
built = fi.ModTime()
|
||||
}
|
||||
if built.IsZero() {
|
||||
return true
|
||||
}
|
||||
|
||||
olderThan := func(file string) bool {
|
||||
fi, err := os.Stat(file)
|
||||
return err != nil || fi.ModTime().After(built)
|
||||
}
|
||||
|
||||
// Package is stale if a dependency is, or if a dependency is newer.
|
||||
for _, p1 := range p.deps {
|
||||
if p1.Stale || p1.target != "" && olderThan(p1.target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// As a courtesy to developers installing new versions of the compiler
|
||||
// frequently, define that packages are stale if they are
|
||||
// older than the compiler, and commands if they are older than
|
||||
// the linker. This heuristic will not work if the binaries are
|
||||
// back-dated, as some binary distributions may do, but it does handle
|
||||
// a very common case.
|
||||
// See issue 3036.
|
||||
// Assume code in $GOROOT is up to date, since it may not be writeable.
|
||||
// See issue 4106.
|
||||
if p.Root != goroot {
|
||||
if olderThan(buildToolchain.compiler()) {
|
||||
return true
|
||||
}
|
||||
if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Have installed copy, probably built using current compilers,
|
||||
// and built after its imported packages. The only reason now
|
||||
// that we'd have to rebuild it is if the sources were newer than
|
||||
// the package. If a package p is not in the same tree as any
|
||||
// package named on the command-line, assume it is up-to-date
|
||||
// no matter what the modification times on the source files indicate.
|
||||
// This avoids rebuilding $GOROOT packages when people are
|
||||
// working outside the Go root, and it effectively makes each tree
|
||||
// listed in $GOPATH a separate compilation world.
|
||||
// See issue 3149.
|
||||
if p.Root != "" && !topRoot[p.Root] {
|
||||
return false
|
||||
}
|
||||
|
||||
srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
|
||||
for _, src := range srcs {
|
||||
if olderThan(filepath.Join(p.Dir, src)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var cwd, _ = os.Getwd()
|
||||
|
||||
var cmdCache = map[string]*Package{}
|
||||
|
||||
// loadPackage is like loadImport but is used for command-line arguments,
|
||||
// not for paths found in import statements. In addition to ordinary import paths,
|
||||
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
|
||||
// in the Go command directory, as well as paths to those directories.
|
||||
func loadPackage(arg string, stk *importStack) *Package {
|
||||
if build.IsLocalImport(arg) {
|
||||
dir := arg
|
||||
if !filepath.IsAbs(dir) {
|
||||
if abs, err := filepath.Abs(dir); err == nil {
|
||||
// interpret relative to current directory
|
||||
dir = abs
|
||||
}
|
||||
}
|
||||
if sub, ok := hasSubdir(gorootSrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
|
||||
arg = sub
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(arg, "cmd/") {
|
||||
if p := cmdCache[arg]; p != nil {
|
||||
return p
|
||||
}
|
||||
stk.push(arg)
|
||||
defer stk.pop()
|
||||
|
||||
if strings.Contains(arg[4:], "/") {
|
||||
p := &Package{
|
||||
Error: &PackageError{
|
||||
ImportStack: stk.copy(),
|
||||
Err: fmt.Sprintf("invalid import path: cmd/... is reserved for Go commands"),
|
||||
hard: true,
|
||||
},
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)
|
||||
bp.ImportPath = arg
|
||||
bp.Goroot = true
|
||||
bp.BinDir = gorootBin
|
||||
if gobin != "" {
|
||||
bp.BinDir = gobin
|
||||
}
|
||||
bp.Root = goroot
|
||||
bp.SrcRoot = gorootSrc
|
||||
p := new(Package)
|
||||
cmdCache[arg] = p
|
||||
p.load(stk, bp, err)
|
||||
if p.Error == nil && p.Name != "main" {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.copy(),
|
||||
Err: fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Wasn't a command; must be a package.
|
||||
// If it is a local import path but names a standard package,
|
||||
// we treat it as if the user specified the standard package.
|
||||
// This lets you run go test ./ioutil in package io and be
|
||||
// referring to io/ioutil rather than a hypothetical import of
|
||||
// "./ioutil".
|
||||
if build.IsLocalImport(arg) {
|
||||
bp, _ := buildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
|
||||
if bp.ImportPath != "" && bp.ImportPath != "." {
|
||||
arg = bp.ImportPath
|
||||
}
|
||||
}
|
||||
|
||||
return loadImport(arg, cwd, stk, nil)
|
||||
}
|
||||
|
||||
// packages returns the packages named by the
|
||||
// command line arguments 'args'. If a named package
|
||||
// cannot be loaded at all (for example, if the directory does not exist),
|
||||
// then packages prints an error and does not include that
|
||||
// package in the results. However, if errors occur trying
|
||||
// to load dependencies of a named package, the named
|
||||
// package is still returned, with p.Incomplete = true
|
||||
// and details in p.DepsErrors.
|
||||
func packages(args []string) []*Package {
|
||||
var pkgs []*Package
|
||||
for _, pkg := range packagesAndErrors(args) {
|
||||
if pkg.Error != nil {
|
||||
errorf("can't load package: %s", pkg.Error)
|
||||
continue
|
||||
}
|
||||
pkgs = append(pkgs, pkg)
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
||||
// packagesAndErrors is like 'packages' but returns a
|
||||
// *Package for every argument, even the ones that
|
||||
// cannot be loaded at all.
|
||||
// The packages that fail to load will have p.Error != nil.
|
||||
func packagesAndErrors(args []string) []*Package {
|
||||
if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
|
||||
return []*Package{goFilesPackage(args)}
|
||||
}
|
||||
|
||||
args = importPaths(args)
|
||||
var pkgs []*Package
|
||||
var stk importStack
|
||||
var set = make(map[string]bool)
|
||||
|
||||
for _, arg := range args {
|
||||
if !set[arg] {
|
||||
pkgs = append(pkgs, loadPackage(arg, &stk))
|
||||
set[arg] = true
|
||||
}
|
||||
}
|
||||
computeStale(pkgs...)
|
||||
|
||||
return pkgs
|
||||
}
|
||||
|
||||
// packagesForBuild is like 'packages' but fails if any of
|
||||
// the packages or their dependencies have errors
|
||||
// (cannot be built).
|
||||
func packagesForBuild(args []string) []*Package {
|
||||
pkgs := packagesAndErrors(args)
|
||||
printed := map[*PackageError]bool{}
|
||||
for _, pkg := range pkgs {
|
||||
if pkg.Error != nil {
|
||||
errorf("can't load package: %s", pkg.Error)
|
||||
}
|
||||
for _, err := range pkg.DepsErrors {
|
||||
// Since these are errors in dependencies,
|
||||
// the same error might show up multiple times,
|
||||
// once in each package that depends on it.
|
||||
// Only print each once.
|
||||
if !printed[err] {
|
||||
printed[err] = true
|
||||
errorf("%s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
exitIfErrors()
|
||||
return pkgs
|
||||
}
|
||||
|
||||
// hasSubdir reports whether dir is a subdirectory of
|
||||
// (possibly multiple levels below) root.
|
||||
// If so, it sets rel to the path fragment that must be
|
||||
// appended to root to reach dir.
|
||||
func hasSubdir(root, dir string) (rel string, ok bool) {
|
||||
if p, err := filepath.EvalSymlinks(root); err == nil {
|
||||
root = p
|
||||
}
|
||||
if p, err := filepath.EvalSymlinks(dir); err == nil {
|
||||
dir = p
|
||||
}
|
||||
const sep = string(filepath.Separator)
|
||||
root = filepath.Clean(root)
|
||||
if !strings.HasSuffix(root, sep) {
|
||||
root += sep
|
||||
}
|
||||
dir = filepath.Clean(dir)
|
||||
if !strings.HasPrefix(dir, root) {
|
||||
return "", false
|
||||
}
|
||||
return filepath.ToSlash(dir[len(root):]), true
|
||||
}
|
73
libgo/go/cmd/go/pkg_test.go
Normal file
73
libgo/go/cmd/go/pkg_test.go
Normal file
@ -0,0 +1,73 @@
|
||||
// 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 (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var foldDupTests = []struct {
|
||||
list []string
|
||||
f1, f2 string
|
||||
}{
|
||||
{stringList("math/rand", "math/big"), "", ""},
|
||||
{stringList("math", "strings"), "", ""},
|
||||
{stringList("strings"), "", ""},
|
||||
{stringList("strings", "strings"), "strings", "strings"},
|
||||
{stringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
|
||||
}
|
||||
|
||||
func TestFoldDup(t *testing.T) {
|
||||
for _, tt := range foldDupTests {
|
||||
f1, f2 := foldDup(tt.list)
|
||||
if f1 != tt.f1 || f2 != tt.f2 {
|
||||
t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var parseMetaGoImportsTests = []struct {
|
||||
in string
|
||||
out []metaImport
|
||||
}{
|
||||
{
|
||||
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
|
||||
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
|
||||
},
|
||||
{
|
||||
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
|
||||
<meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
|
||||
[]metaImport{
|
||||
{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
|
||||
{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
|
||||
},
|
||||
},
|
||||
{
|
||||
`<head>
|
||||
<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
|
||||
</head>`,
|
||||
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
|
||||
},
|
||||
{
|
||||
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
|
||||
<body>`,
|
||||
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
|
||||
},
|
||||
}
|
||||
|
||||
func TestParseMetaGoImports(t *testing.T) {
|
||||
for i, tt := range parseMetaGoImportsTests {
|
||||
out, err := parseMetaGoImports(strings.NewReader(tt.in))
|
||||
if err != nil {
|
||||
t.Errorf("test#%d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(out, tt.out) {
|
||||
t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
143
libgo/go/cmd/go/run.go
Normal file
143
libgo/go/cmd/go/run.go
Normal file
@ -0,0 +1,143 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var execCmd []string // -exec flag, for run and test
|
||||
|
||||
func findExecCmd() []string {
|
||||
if execCmd != nil {
|
||||
return execCmd
|
||||
}
|
||||
execCmd = []string{} // avoid work the second time
|
||||
if goos == runtime.GOOS && goarch == runtime.GOARCH {
|
||||
return execCmd
|
||||
}
|
||||
path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
|
||||
if err == nil {
|
||||
execCmd = []string{path}
|
||||
}
|
||||
return execCmd
|
||||
}
|
||||
|
||||
var cmdRun = &Command{
|
||||
UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
|
||||
Short: "compile and run Go program",
|
||||
Long: `
|
||||
Run compiles and runs the main package comprising the named Go source files.
|
||||
A Go source file is defined to be a file ending in a literal ".go" suffix.
|
||||
|
||||
By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
|
||||
If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
|
||||
If the -exec flag is not given, GOOS or GOARCH is different from the system
|
||||
default, and a program named go_$GOOS_$GOARCH_exec can be found
|
||||
on the current search path, 'go run' invokes the binary using that program,
|
||||
for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
|
||||
cross-compiled programs when a simulator or other execution method is
|
||||
available.
|
||||
|
||||
For more about build flags, see 'go help build'.
|
||||
|
||||
See also: go build.
|
||||
`,
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmdRun.Run = runRun // break init loop
|
||||
|
||||
addBuildFlags(cmdRun)
|
||||
cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
|
||||
}
|
||||
|
||||
func printStderr(args ...interface{}) (int, error) {
|
||||
return fmt.Fprint(os.Stderr, args...)
|
||||
}
|
||||
|
||||
func runRun(cmd *Command, args []string) {
|
||||
raceInit()
|
||||
var b builder
|
||||
b.init()
|
||||
b.print = printStderr
|
||||
i := 0
|
||||
for i < len(args) && strings.HasSuffix(args[i], ".go") {
|
||||
i++
|
||||
}
|
||||
files, cmdArgs := args[:i], args[i:]
|
||||
if len(files) == 0 {
|
||||
fatalf("go run: no go files listed")
|
||||
}
|
||||
for _, file := range files {
|
||||
if strings.HasSuffix(file, "_test.go") {
|
||||
// goFilesPackage is going to assign this to TestGoFiles.
|
||||
// Reject since it won't be part of the build.
|
||||
fatalf("go run: cannot run *_test.go files (%s)", file)
|
||||
}
|
||||
}
|
||||
p := goFilesPackage(files)
|
||||
if p.Error != nil {
|
||||
fatalf("%s", p.Error)
|
||||
}
|
||||
p.omitDWARF = true
|
||||
for _, err := range p.DepsErrors {
|
||||
errorf("%s", err)
|
||||
}
|
||||
exitIfErrors()
|
||||
if p.Name != "main" {
|
||||
fatalf("go run: cannot run non-main package")
|
||||
}
|
||||
p.target = "" // must build - not up to date
|
||||
var src string
|
||||
if len(p.GoFiles) > 0 {
|
||||
src = p.GoFiles[0]
|
||||
} else if len(p.CgoFiles) > 0 {
|
||||
src = p.CgoFiles[0]
|
||||
} else {
|
||||
// this case could only happen if the provided source uses cgo
|
||||
// while cgo is disabled.
|
||||
hint := ""
|
||||
if !buildContext.CgoEnabled {
|
||||
hint = " (cgo is disabled)"
|
||||
}
|
||||
fatalf("go run: no suitable source files%s", hint)
|
||||
}
|
||||
p.exeName = src[:len(src)-len(".go")] // name temporary executable for first go file
|
||||
a1 := b.action(modeBuild, modeBuild, p)
|
||||
a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
|
||||
b.do(a)
|
||||
}
|
||||
|
||||
// runProgram is the action for running a binary that has already
|
||||
// been compiled. We ignore exit status.
|
||||
func (b *builder) runProgram(a *action) error {
|
||||
cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
|
||||
if buildN || buildX {
|
||||
b.showcmd("", "%s", strings.Join(cmdline, " "))
|
||||
if buildN {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
runStdin(cmdline)
|
||||
return nil
|
||||
}
|
||||
|
||||
// runStdin is like run, but connects Stdin.
|
||||
func runStdin(cmdline []string) {
|
||||
cmd := exec.Command(cmdline[0], cmdline[1:]...)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
startSigHandlers()
|
||||
if err := cmd.Run(); err != nil {
|
||||
errorf("%v", err)
|
||||
}
|
||||
}
|
23
libgo/go/cmd/go/script
Normal file
23
libgo/go/cmd/go/script
Normal file
@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
|
||||
x() {
|
||||
echo '--- ' "$@"
|
||||
"$@"
|
||||
echo '---'
|
||||
echo
|
||||
}
|
||||
|
||||
x go help
|
||||
x go help build
|
||||
x go help clean
|
||||
x go help install
|
||||
x go help fix
|
||||
x go help fmt
|
||||
x go help get
|
||||
x go help list
|
||||
x go help test
|
||||
x go help version
|
||||
x go help vet
|
||||
x go help gopath
|
||||
x go help importpath
|
||||
x go help remote
|
352
libgo/go/cmd/go/script.txt
Normal file
352
libgo/go/cmd/go/script.txt
Normal file
@ -0,0 +1,352 @@
|
||||
--- go help
|
||||
usage: go command [arguments]
|
||||
|
||||
go manages Go source code.
|
||||
|
||||
The commands are:
|
||||
|
||||
build compile and install packages and dependencies
|
||||
clean remove intermediate objects
|
||||
fix run gofix on packages
|
||||
fmt run gofmt -w on packages
|
||||
get download and install packages and dependencies
|
||||
install install packages and dependencies
|
||||
list list packages
|
||||
test test packages
|
||||
version print Go version
|
||||
vet run govet on packages
|
||||
|
||||
Use "go help [command]" for more information about a command.
|
||||
|
||||
Additional help topics:
|
||||
|
||||
gopath GOPATH environment variable
|
||||
importpath description of import paths
|
||||
remote remote import path syntax
|
||||
|
||||
Use "go help [topic]" for more information about that topic.
|
||||
|
||||
---
|
||||
|
||||
--- go help build
|
||||
usage: go build [-n] [-v] [importpath...]
|
||||
|
||||
Build compiles the packages named by the import paths,
|
||||
along with their dependencies, but it does not install the results.
|
||||
|
||||
The -n flag prints the commands but does not run them.
|
||||
The -v flag prints the commands.
|
||||
|
||||
For more about import paths, see 'go help importpath'.
|
||||
|
||||
See also: go install, go get, go clean.
|
||||
---
|
||||
|
||||
--- go help clean
|
||||
usage: go clean [-nuke] [importpath...]
|
||||
|
||||
Clean removes intermediate object files generated during
|
||||
the compilation of the packages named by the import paths,
|
||||
but by default it does not remove the installed package binaries.
|
||||
|
||||
The -nuke flag causes clean to remove the installed package binaries too.
|
||||
|
||||
TODO: Clean does not clean dependencies of the packages.
|
||||
|
||||
For more about import paths, see 'go help importpath'.
|
||||
---
|
||||
|
||||
--- go help install
|
||||
usage: go install [-n] [-v] [importpath...]
|
||||
|
||||
Install compiles and installs the packages named by the import paths,
|
||||
along with their dependencies.
|
||||
|
||||
The -n flag prints the commands but does not run them.
|
||||
The -v flag prints the commands.
|
||||
|
||||
For more about import paths, see 'go help importpath'.
|
||||
|
||||
See also: go build, go get, go clean.
|
||||
---
|
||||
|
||||
--- go help fix
|
||||
usage: go fix [importpath...]
|
||||
|
||||
Fix runs the gofix command on the packages named by the import paths.
|
||||
|
||||
For more about gofix, see 'godoc gofix'.
|
||||
For more about import paths, see 'go help importpath'.
|
||||
|
||||
To run gofix with specific options, run gofix itself.
|
||||
|
||||
See also: go fmt, go vet.
|
||||
---
|
||||
|
||||
--- go help fmt
|
||||
usage: go fmt [importpath...]
|
||||
|
||||
Fmt runs the command 'gofmt -w' on the packages named by the import paths.
|
||||
|
||||
For more about gofmt, see 'godoc gofmt'.
|
||||
For more about import paths, see 'go help importpath'.
|
||||
|
||||
To run gofmt with specific options, run gofmt itself.
|
||||
|
||||
See also: go fix, go vet.
|
||||
---
|
||||
|
||||
--- go help get
|
||||
usage: go get [importpath...]
|
||||
|
||||
Get downloads and installs the packages named by the import paths,
|
||||
along with their dependencies.
|
||||
|
||||
After downloading the code, 'go get' looks for a tag beginning
|
||||
with "go." that corresponds to the local Go version.
|
||||
For Go "release.r58" it looks for a tag named "go.r58".
|
||||
For "weekly.2011-06-03" it looks for "go.weekly.2011-06-03".
|
||||
If the specific "go.X" tag is not found, it uses the latest earlier
|
||||
version it can find. Otherwise, it uses the default version for
|
||||
the version control system: HEAD for git, tip for Mercurial,
|
||||
and so on.
|
||||
|
||||
TODO: Explain versions better.
|
||||
|
||||
For more about import paths, see 'go help importpath'.
|
||||
|
||||
For more about how 'go get' finds source code to
|
||||
download, see 'go help remote'.
|
||||
|
||||
See also: go build, go install, go clean.
|
||||
---
|
||||
|
||||
--- go help list
|
||||
usage: go list [-f format] [-json] [importpath...]
|
||||
|
||||
List lists the packages named by the import paths.
|
||||
|
||||
The default output shows the package name and file system location:
|
||||
|
||||
books /home/you/src/google-api-go-client.googlecode.com/hg/books/v1
|
||||
oauth /home/you/src/goauth2.googlecode.com/hg/oauth
|
||||
sqlite /home/you/src/gosqlite.googlecode.com/hg/sqlite
|
||||
|
||||
The -f flag specifies an alternate format for the list,
|
||||
using the syntax of package template. The default output
|
||||
is equivalent to -f '{{.Name}} {{.Dir}}' The struct
|
||||
being passed to the template is:
|
||||
|
||||
type Package struct {
|
||||
Name string // package name
|
||||
Doc string // package documentation string
|
||||
GoFiles []string // names of Go source files in package
|
||||
ImportPath string // import path denoting package
|
||||
Imports []string // import paths used by this package
|
||||
Deps []string // all (recursively) imported dependencies
|
||||
Dir string // directory containing package sources
|
||||
Version string // version of installed package
|
||||
}
|
||||
|
||||
The -json flag causes the package data to be printed in JSON format.
|
||||
|
||||
For more about import paths, see 'go help importpath'.
|
||||
---
|
||||
|
||||
--- go help test
|
||||
usage: go test [importpath...]
|
||||
|
||||
Test runs gotest to test the packages named by the import paths.
|
||||
It prints a summary of the test results in the format:
|
||||
|
||||
test archive/tar
|
||||
FAIL archive/zip
|
||||
test compress/gzip
|
||||
...
|
||||
|
||||
followed by gotest output for each failed package.
|
||||
|
||||
For more about import paths, see 'go help importpath'.
|
||||
|
||||
See also: go build, go compile, go vet.
|
||||
---
|
||||
|
||||
--- go help version
|
||||
usage: go version
|
||||
|
||||
Version prints the Go version, as reported by runtime.Version.
|
||||
---
|
||||
|
||||
--- go help vet
|
||||
usage: go vet [importpath...]
|
||||
|
||||
Vet runs the govet command on the packages named by the import paths.
|
||||
|
||||
For more about govet, see 'godoc govet'.
|
||||
For more about import paths, see 'go help importpath'.
|
||||
|
||||
To run govet with specific options, run govet itself.
|
||||
|
||||
See also: go fmt, go fix.
|
||||
---
|
||||
|
||||
--- go help gopath
|
||||
The GOPATH environment variable lists places to look for Go code.
|
||||
On Unix, the value is a colon-separated string.
|
||||
On Windows, the value is a semicolon-separated string.
|
||||
On Plan 9, the value is a list.
|
||||
|
||||
GOPATH must be set to build and install packages outside the
|
||||
standard Go tree.
|
||||
|
||||
Each directory listed in GOPATH must have a prescribed structure:
|
||||
|
||||
The src/ directory holds source code. The path below 'src'
|
||||
determines the import path or executable name.
|
||||
|
||||
The pkg/ directory holds installed package objects.
|
||||
As in the Go tree, each target operating system and
|
||||
architecture pair has its own subdirectory of pkg
|
||||
(pkg/GOOS_GOARCH).
|
||||
|
||||
If DIR is a directory listed in the GOPATH, a package with
|
||||
source in DIR/src/foo/bar can be imported as "foo/bar" and
|
||||
has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
|
||||
|
||||
The bin/ directory holds compiled commands.
|
||||
Each command is named for its source directory, but only
|
||||
the final element, not the entire path. That is, the
|
||||
command with source in DIR/src/foo/quux is installed into
|
||||
DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
|
||||
so that you can add DIR/bin to your PATH to get at the
|
||||
installed commands.
|
||||
|
||||
Here's an example directory layout:
|
||||
|
||||
GOPATH=/home/user/gocode
|
||||
|
||||
/home/user/gocode/
|
||||
src/
|
||||
foo/
|
||||
bar/ (go code in package bar)
|
||||
x.go
|
||||
quux/ (go code in package main)
|
||||
y.go
|
||||
bin/
|
||||
quux (installed command)
|
||||
pkg/
|
||||
linux_amd64/
|
||||
foo/
|
||||
bar.a (installed package object)
|
||||
|
||||
Go searches each directory listed in GOPATH to find source code,
|
||||
but new packages are always downloaded into the first directory
|
||||
in the list.
|
||||
---
|
||||
|
||||
--- go help importpath
|
||||
Many commands apply to a set of packages named by import paths:
|
||||
|
||||
go action [importpath...]
|
||||
|
||||
An import path that is a rooted path or that begins with
|
||||
a . or .. element is interpreted as a file system path and
|
||||
denotes the package in that directory.
|
||||
|
||||
Otherwise, the import path P denotes the package found in
|
||||
the directory DIR/src/P for some DIR listed in the GOPATH
|
||||
environment variable (see 'go help gopath').
|
||||
|
||||
If no import paths are given, the action applies to the
|
||||
package in the current directory.
|
||||
|
||||
The special import path "all" expands to all package directories
|
||||
found in all the GOPATH trees. For example, 'go list all'
|
||||
lists all the packages on the local system.
|
||||
|
||||
An import path can also name a package to be downloaded from
|
||||
a remote repository. Run 'go help remote' for details.
|
||||
|
||||
Every package in a program must have a unique import path.
|
||||
By convention, this is arranged by starting each path with a
|
||||
unique prefix that belongs to you. For example, paths used
|
||||
internally at Google all begin with 'google', and paths
|
||||
denoting remote repositories begin with the path to the code,
|
||||
such as 'project.googlecode.com/'.
|
||||
---
|
||||
|
||||
--- go help remote
|
||||
An import path (see 'go help importpath') denotes a package
|
||||
stored in the local file system. Certain import paths also
|
||||
describe how to obtain the source code for the package using
|
||||
a revision control system.
|
||||
|
||||
A few common code hosting sites have special syntax:
|
||||
|
||||
BitBucket (Mercurial)
|
||||
|
||||
import "bitbucket.org/user/project"
|
||||
import "bitbucket.org/user/project/sub/directory"
|
||||
|
||||
GitHub (Git)
|
||||
|
||||
import "github.com/user/project"
|
||||
import "github.com/user/project/sub/directory"
|
||||
|
||||
Google Code Project Hosting (Git, Mercurial, Subversion)
|
||||
|
||||
import "project.googlecode.com/git"
|
||||
import "project.googlecode.com/git/sub/directory"
|
||||
|
||||
import "project.googlecode.com/hg"
|
||||
import "project.googlecode.com/hg/sub/directory"
|
||||
|
||||
import "project.googlecode.com/svn/trunk"
|
||||
import "project.googlecode.com/svn/trunk/sub/directory"
|
||||
|
||||
Launchpad (Bazaar)
|
||||
|
||||
import "launchpad.net/project"
|
||||
import "launchpad.net/project/series"
|
||||
import "launchpad.net/project/series/sub/directory"
|
||||
|
||||
import "launchpad.net/~user/project/branch"
|
||||
import "launchpad.net/~user/project/branch/sub/directory"
|
||||
|
||||
For code hosted on other servers, an import path of the form
|
||||
|
||||
repository.vcs/path
|
||||
|
||||
specifies the given repository, with or without the .vcs suffix,
|
||||
using the named version control system, and then the path inside
|
||||
that repository. The supported version control systems are:
|
||||
|
||||
Bazaar .bzr
|
||||
Git .git
|
||||
Mercurial .hg
|
||||
Subversion .svn
|
||||
|
||||
For example,
|
||||
|
||||
import "example.org/user/foo.hg"
|
||||
|
||||
denotes the root directory of the Mercurial repository at
|
||||
example.org/user/foo or foo.hg, and
|
||||
|
||||
import "example.org/repo.git/foo/bar"
|
||||
|
||||
denotes the foo/bar directory of the Git repository at
|
||||
example.com/repo or repo.git.
|
||||
|
||||
When a version control system supports multiple protocols,
|
||||
each is tried in turn when downloading. For example, a Git
|
||||
download tries git://, then https://, then http://.
|
||||
|
||||
New downloaded packages are written to the first directory
|
||||
listed in the GOPATH environment variable (see 'go help gopath').
|
||||
|
||||
The go command attempts to download the version of the
|
||||
package appropriate for the Go release being used.
|
||||
Run 'go help install' for more.
|
||||
---
|
||||
|
31
libgo/go/cmd/go/signal.go
Normal file
31
libgo/go/cmd/go/signal.go
Normal file
@ -0,0 +1,31 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// interrupted is closed, if go process is interrupted.
|
||||
var interrupted = make(chan struct{})
|
||||
|
||||
// processSignals setups signal handler.
|
||||
func processSignals() {
|
||||
sig := make(chan os.Signal)
|
||||
signal.Notify(sig, signalsToIgnore...)
|
||||
go func() {
|
||||
<-sig
|
||||
close(interrupted)
|
||||
}()
|
||||
}
|
||||
|
||||
var onceProcessSignals sync.Once
|
||||
|
||||
// startSigHandlers start signal handlers.
|
||||
func startSigHandlers() {
|
||||
onceProcessSignals.Do(processSignals)
|
||||
}
|
17
libgo/go/cmd/go/signal_notunix.go
Normal file
17
libgo/go/cmd/go/signal_notunix.go
Normal file
@ -0,0 +1,17 @@
|
||||
// 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 plan9 windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
var signalsToIgnore = []os.Signal{os.Interrupt}
|
||||
|
||||
// signalTrace is the signal to send to make a Go program
|
||||
// crash with a stack trace.
|
||||
var signalTrace os.Signal = nil
|
18
libgo/go/cmd/go/signal_unix.go
Normal file
18
libgo/go/cmd/go/signal_unix.go
Normal file
@ -0,0 +1,18 @@
|
||||
// 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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT}
|
||||
|
||||
// signalTrace is the signal to send to make a Go program
|
||||
// crash with a stack trace.
|
||||
var signalTrace os.Signal = syscall.SIGQUIT
|
100
libgo/go/cmd/go/tag_test.go
Normal file
100
libgo/go/cmd/go/tag_test.go
Normal file
@ -0,0 +1,100 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
var selectTagTestTags = []string{
|
||||
"go.r58",
|
||||
"go.r58.1",
|
||||
"go.r59",
|
||||
"go.r59.1",
|
||||
"go.r61",
|
||||
"go.r61.1",
|
||||
"go.weekly.2010-01-02",
|
||||
"go.weekly.2011-10-12",
|
||||
"go.weekly.2011-10-12.1",
|
||||
"go.weekly.2011-10-14",
|
||||
"go.weekly.2011-11-01",
|
||||
"go1",
|
||||
"go1.0.1",
|
||||
"go1.999",
|
||||
"go1.9.2",
|
||||
"go5",
|
||||
|
||||
// these should be ignored:
|
||||
"release.r59",
|
||||
"release.r59.1",
|
||||
"release",
|
||||
"weekly.2011-10-12",
|
||||
"weekly.2011-10-12.1",
|
||||
"weekly",
|
||||
"foo",
|
||||
"bar",
|
||||
"go.f00",
|
||||
"go!r60",
|
||||
"go.1999-01-01",
|
||||
"go.2x",
|
||||
"go.20000000000000",
|
||||
"go.2.",
|
||||
"go.2.0",
|
||||
"go2x",
|
||||
"go20000000000000",
|
||||
"go2.",
|
||||
"go2.0",
|
||||
}
|
||||
|
||||
var selectTagTests = []struct {
|
||||
version string
|
||||
selected string
|
||||
}{
|
||||
/*
|
||||
{"release.r57", ""},
|
||||
{"release.r58.2", "go.r58.1"},
|
||||
{"release.r59", "go.r59"},
|
||||
{"release.r59.1", "go.r59.1"},
|
||||
{"release.r60", "go.r59.1"},
|
||||
{"release.r60.1", "go.r59.1"},
|
||||
{"release.r61", "go.r61"},
|
||||
{"release.r66", "go.r61.1"},
|
||||
{"weekly.2010-01-01", ""},
|
||||
{"weekly.2010-01-02", "go.weekly.2010-01-02"},
|
||||
{"weekly.2010-01-02.1", "go.weekly.2010-01-02"},
|
||||
{"weekly.2010-01-03", "go.weekly.2010-01-02"},
|
||||
{"weekly.2011-10-12", "go.weekly.2011-10-12"},
|
||||
{"weekly.2011-10-12.1", "go.weekly.2011-10-12.1"},
|
||||
{"weekly.2011-10-13", "go.weekly.2011-10-12.1"},
|
||||
{"weekly.2011-10-14", "go.weekly.2011-10-14"},
|
||||
{"weekly.2011-10-14.1", "go.weekly.2011-10-14"},
|
||||
{"weekly.2011-11-01", "go.weekly.2011-11-01"},
|
||||
{"weekly.2014-01-01", "go.weekly.2011-11-01"},
|
||||
{"weekly.3000-01-01", "go.weekly.2011-11-01"},
|
||||
{"go1", "go1"},
|
||||
{"go1.1", "go1.0.1"},
|
||||
{"go1.998", "go1.9.2"},
|
||||
{"go1.1000", "go1.999"},
|
||||
{"go6", "go5"},
|
||||
|
||||
// faulty versions:
|
||||
{"release.f00", ""},
|
||||
{"weekly.1999-01-01", ""},
|
||||
{"junk", ""},
|
||||
{"", ""},
|
||||
{"go2x", ""},
|
||||
{"go200000000000", ""},
|
||||
{"go2.", ""},
|
||||
{"go2.0", ""},
|
||||
*/
|
||||
{"anything", "go1"},
|
||||
}
|
||||
|
||||
func TestSelectTag(t *testing.T) {
|
||||
for _, c := range selectTagTests {
|
||||
selected := selectTag(c.version, selectTagTestTags)
|
||||
if selected != c.selected {
|
||||
t.Errorf("selectTag(%q) = %q, want %q", c.version, selected, c.selected)
|
||||
}
|
||||
}
|
||||
}
|
820
libgo/go/cmd/go/test.bash
Normal file
820
libgo/go/cmd/go/test.bash
Normal file
@ -0,0 +1,820 @@
|
||||
#!/bin/bash
|
||||
# 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.
|
||||
|
||||
set -e
|
||||
go build -o testgo
|
||||
go() {
|
||||
echo TEST ERROR: ran go, not testgo: go "$@" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
started=false
|
||||
TEST() {
|
||||
if $started; then
|
||||
stop
|
||||
fi
|
||||
echo TEST: "$@"
|
||||
started=true
|
||||
ok=true
|
||||
}
|
||||
stop() {
|
||||
if ! $started; then
|
||||
echo TEST ERROR: stop missing start >&2
|
||||
exit 2
|
||||
fi
|
||||
started=false
|
||||
if $ok; then
|
||||
echo PASS
|
||||
else
|
||||
echo FAIL
|
||||
allok=false
|
||||
fi
|
||||
}
|
||||
|
||||
ok=true
|
||||
allok=true
|
||||
|
||||
unset GOBIN
|
||||
unset GOPATH
|
||||
unset GOROOT
|
||||
|
||||
TEST 'file:line in error messages'
|
||||
# Test that error messages have file:line information at beginning of
|
||||
# the line. Also test issue 4917: that the error is on stderr.
|
||||
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
|
||||
fn=$d/err.go
|
||||
echo "package main" > $fn
|
||||
echo 'import "bar"' >> $fn
|
||||
./testgo run $fn 2>$d/err.out || true
|
||||
if ! grep -q "^$fn:" $d/err.out; then
|
||||
echo "missing file:line in error message"
|
||||
cat $d/err.out
|
||||
ok=false
|
||||
fi
|
||||
rm -r $d
|
||||
|
||||
# Test local (./) imports.
|
||||
testlocal() {
|
||||
local="$1"
|
||||
TEST local imports $2 '(easy)'
|
||||
./testgo build -o hello "testdata/$local/easy.go"
|
||||
./hello >hello.out
|
||||
if ! grep -q '^easysub\.Hello' hello.out; then
|
||||
echo "testdata/$local/easy.go did not generate expected output"
|
||||
cat hello.out
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST local imports $2 '(easysub)'
|
||||
./testgo build -o hello "testdata/$local/easysub/main.go"
|
||||
./hello >hello.out
|
||||
if ! grep -q '^easysub\.Hello' hello.out; then
|
||||
echo "testdata/$local/easysub/main.go did not generate expected output"
|
||||
cat hello.out
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST local imports $2 '(hard)'
|
||||
./testgo build -o hello "testdata/$local/hard.go"
|
||||
./hello >hello.out
|
||||
if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then
|
||||
echo "testdata/$local/hard.go did not generate expected output"
|
||||
cat hello.out
|
||||
ok=false
|
||||
fi
|
||||
|
||||
rm -f hello.out hello
|
||||
|
||||
# Test that go install x.go fails.
|
||||
TEST local imports $2 '(go install should fail)'
|
||||
if ./testgo install "testdata/$local/easy.go" >/dev/null 2>&1; then
|
||||
echo "go install testdata/$local/easy.go succeeded"
|
||||
ok=false
|
||||
fi
|
||||
}
|
||||
|
||||
# Test local imports
|
||||
testlocal local ''
|
||||
|
||||
# Test local imports again, with bad characters in the directory name.
|
||||
bad='#$%:, &()*;<=>?\^{}'
|
||||
rm -rf "testdata/$bad"
|
||||
cp -R testdata/local "testdata/$bad"
|
||||
testlocal "$bad" 'with bad characters in path'
|
||||
rm -rf "testdata/$bad"
|
||||
|
||||
TEST error message for syntax error in test go file says FAIL
|
||||
export GOPATH=$(pwd)/testdata
|
||||
if ./testgo test syntaxerror 2>testdata/err; then
|
||||
echo 'go test syntaxerror succeeded'
|
||||
ok=false
|
||||
elif ! grep FAIL testdata/err >/dev/null; then
|
||||
echo 'go test did not say FAIL:'
|
||||
cat testdata/err
|
||||
ok=false
|
||||
fi
|
||||
rm -f ./testdata/err
|
||||
unset GOPATH
|
||||
|
||||
TEST wildcards do not look in useless directories
|
||||
export GOPATH=$(pwd)/testdata
|
||||
if ./testgo list ... >testdata/err 2>&1; then
|
||||
echo "go list ... succeeded"
|
||||
ok=false
|
||||
elif ! grep badpkg testdata/err >/dev/null; then
|
||||
echo "go list ... failure does not mention badpkg"
|
||||
cat testdata/err
|
||||
ok=false
|
||||
elif ! ./testgo list m... >testdata/err 2>&1; then
|
||||
echo "go list m... failed"
|
||||
ok=false
|
||||
fi
|
||||
rm -rf ./testdata/err
|
||||
unset GOPATH
|
||||
|
||||
# Test tests with relative imports.
|
||||
TEST relative imports '(go test)'
|
||||
if ! ./testgo test ./testdata/testimport; then
|
||||
echo "go test ./testdata/testimport failed"
|
||||
ok=false
|
||||
fi
|
||||
|
||||
# Test installation with relative imports.
|
||||
TEST relative imports '(go test -i)'
|
||||
if ! ./testgo test -i ./testdata/testimport; then
|
||||
echo "go test -i ./testdata/testimport failed"
|
||||
ok=false
|
||||
fi
|
||||
|
||||
# Test tests with relative imports in packages synthesized
|
||||
# from Go files named on the command line.
|
||||
TEST relative imports in command-line package
|
||||
if ! ./testgo test ./testdata/testimport/*.go; then
|
||||
echo "go test ./testdata/testimport/*.go failed"
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST version control error message includes correct directory
|
||||
export GOPATH=$(pwd)/testdata/shadow/root1
|
||||
if ./testgo get -u foo 2>testdata/err; then
|
||||
echo "go get -u foo succeeded unexpectedly"
|
||||
ok=false
|
||||
elif ! grep testdata/shadow/root1/src/foo testdata/err >/dev/null; then
|
||||
echo "go get -u error does not mention shadow/root1/src/foo:"
|
||||
cat testdata/err
|
||||
ok=false
|
||||
fi
|
||||
unset GOPATH
|
||||
|
||||
TEST go install fails with no buildable files
|
||||
export GOPATH=$(pwd)/testdata
|
||||
export CGO_ENABLED=0
|
||||
if ./testgo install cgotest 2>testdata/err; then
|
||||
echo "go install cgotest succeeded unexpectedly"
|
||||
elif ! grep 'no buildable Go source files' testdata/err >/dev/null; then
|
||||
echo "go install cgotest did not report 'no buildable Go source files'"
|
||||
cat testdata/err
|
||||
ok=false
|
||||
fi
|
||||
unset CGO_ENABLED
|
||||
unset GOPATH
|
||||
|
||||
# Test that without $GOBIN set, binaries get installed
|
||||
# into the GOPATH bin directory.
|
||||
TEST install into GOPATH
|
||||
rm -rf testdata/bin
|
||||
if ! GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
|
||||
echo "go install go-cmd-test failed"
|
||||
ok=false
|
||||
elif ! test -x testdata/bin/go-cmd-test; then
|
||||
echo "go install go-cmd-test did not write to testdata/bin/go-cmd-test"
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST package main_test imports archive not binary
|
||||
export GOBIN=$(pwd)/testdata/bin
|
||||
mkdir -p $GOBIN
|
||||
export GOPATH=$(pwd)/testdata
|
||||
touch ./testdata/src/main_test/m.go
|
||||
if ! ./testgo test main_test; then
|
||||
echo "go test main_test failed without install"
|
||||
ok=false
|
||||
elif ! ./testgo install main_test; then
|
||||
echo "go test main_test failed"
|
||||
ok=false
|
||||
elif [ "$(./testgo list -f '{{.Stale}}' main_test)" != false ]; then
|
||||
echo "after go install, main listed as stale"
|
||||
ok=false
|
||||
elif ! ./testgo test main_test; then
|
||||
echo "go test main_test failed after install"
|
||||
ok=false
|
||||
fi
|
||||
rm -rf $GOBIN
|
||||
unset GOBIN
|
||||
|
||||
# And with $GOBIN set, binaries get installed to $GOBIN.
|
||||
TEST install into GOBIN
|
||||
if ! GOBIN=$(pwd)/testdata/bin1 GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
|
||||
echo "go install go-cmd-test failed"
|
||||
ok=false
|
||||
elif ! test -x testdata/bin1/go-cmd-test; then
|
||||
echo "go install go-cmd-test did not write to testdata/bin1/go-cmd-test"
|
||||
ok=false
|
||||
fi
|
||||
|
||||
# Without $GOBIN set, installing a program outside $GOPATH should fail
|
||||
# (there is nowhere to install it).
|
||||
TEST install without destination fails
|
||||
if ./testgo install testdata/src/go-cmd-test/helloworld.go 2>testdata/err; then
|
||||
echo "go install testdata/src/go-cmd-test/helloworld.go should have failed, did not"
|
||||
ok=false
|
||||
elif ! grep 'no install location for .go files listed on command line' testdata/err; then
|
||||
echo "wrong error:"
|
||||
cat testdata/err
|
||||
ok=false
|
||||
fi
|
||||
rm -f testdata/err
|
||||
|
||||
# With $GOBIN set, should install there.
|
||||
TEST install to GOBIN '(command-line package)'
|
||||
if ! GOBIN=$(pwd)/testdata/bin1 ./testgo install testdata/src/go-cmd-test/helloworld.go; then
|
||||
echo "go install testdata/src/go-cmd-test/helloworld.go failed"
|
||||
ok=false
|
||||
elif ! test -x testdata/bin1/helloworld; then
|
||||
echo "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld"
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST godoc installs into GOBIN
|
||||
d=$(mktemp -d -t testgoXXX)
|
||||
export GOPATH=$d
|
||||
mkdir $d/gobin
|
||||
GOBIN=$d/gobin ./testgo get code.google.com/p/go.tools/cmd/godoc
|
||||
if [ ! -x $d/gobin/godoc ]; then
|
||||
echo did not install godoc to '$GOBIN'
|
||||
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST godoc installs into GOROOT
|
||||
GOROOT=$(./testgo env GOROOT)
|
||||
rm -f $GOROOT/bin/godoc
|
||||
./testgo install code.google.com/p/go.tools/cmd/godoc
|
||||
if [ ! -x $GOROOT/bin/godoc ]; then
|
||||
echo did not install godoc to '$GOROOT/bin'
|
||||
./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST cmd/fix installs into tool
|
||||
GOOS=$(./testgo env GOOS)
|
||||
GOARCH=$(./testgo env GOARCH)
|
||||
rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
|
||||
./testgo install cmd/fix
|
||||
if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
|
||||
echo 'did not install cmd/fix to $GOROOT/pkg/tool'
|
||||
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix
|
||||
ok=false
|
||||
fi
|
||||
rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
|
||||
GOBIN=$d/gobin ./testgo install cmd/fix
|
||||
if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
|
||||
echo 'did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set'
|
||||
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST gopath program installs into GOBIN
|
||||
mkdir $d/src/progname
|
||||
echo 'package main; func main() {}' >$d/src/progname/p.go
|
||||
GOBIN=$d/gobin ./testgo install progname
|
||||
if [ ! -x $d/gobin/progname ]; then
|
||||
echo 'did not install progname to $GOBIN/progname'
|
||||
./testgo list -f 'Target: {{.Target}}' cmd/api
|
||||
ok=false
|
||||
fi
|
||||
rm -f $d/gobin/progname $d/bin/progname
|
||||
|
||||
TEST gopath program installs into GOPATH/bin
|
||||
./testgo install progname
|
||||
if [ ! -x $d/bin/progname ]; then
|
||||
echo 'did not install progname to $GOPATH/bin/progname'
|
||||
./testgo list -f 'Target: {{.Target}}' progname
|
||||
ok=false
|
||||
fi
|
||||
|
||||
unset GOPATH
|
||||
rm -rf $d
|
||||
|
||||
# Reject relative paths in GOPATH.
|
||||
TEST reject relative paths in GOPATH '(command-line package)'
|
||||
if GOPATH=. ./testgo build testdata/src/go-cmd-test/helloworld.go; then
|
||||
echo 'GOPATH="." go build should have failed, did not'
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST reject relative paths in GOPATH
|
||||
if GOPATH=:$(pwd)/testdata:. ./testgo build go-cmd-test; then
|
||||
echo 'GOPATH=":$(pwd)/testdata:." go build should have failed, did not'
|
||||
ok=false
|
||||
fi
|
||||
|
||||
# issue 4104
|
||||
TEST go test with package listed multiple times
|
||||
if [ $(./testgo test fmt fmt fmt fmt fmt | wc -l) -ne 1 ] ; then
|
||||
echo 'go test fmt fmt fmt fmt fmt tested the same package multiple times'
|
||||
ok=false
|
||||
fi
|
||||
|
||||
# ensure that output of 'go list' is consistent between runs
|
||||
TEST go list is consistent
|
||||
./testgo list std > test_std.list
|
||||
if ! ./testgo list std | cmp -s test_std.list - ; then
|
||||
echo "go list std ordering is inconsistent"
|
||||
ok=false
|
||||
fi
|
||||
rm -f test_std.list
|
||||
|
||||
# issue 4096. Validate the output of unsuccessful go install foo/quxx
|
||||
TEST unsuccessful go install should mention missing package
|
||||
if [ $(./testgo install 'foo/quxx' 2>&1 | grep -c 'cannot find package "foo/quxx" in any of') -ne 1 ] ; then
|
||||
echo 'go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of'
|
||||
ok=false
|
||||
fi
|
||||
# test GOROOT search failure is reported
|
||||
TEST GOROOT search failure reporting
|
||||
if [ $(./testgo install 'foo/quxx' 2>&1 | egrep -c 'foo/quxx \(from \$GOROOT\)$') -ne 1 ] ; then
|
||||
echo 'go install foo/quxx expected error: .*foo/quxx (from $GOROOT)'
|
||||
ok=false
|
||||
fi
|
||||
# test multiple GOPATH entries are reported separately
|
||||
TEST multiple GOPATH entries reported separately
|
||||
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/./src/foo/quxx') -ne 2 ] ; then
|
||||
echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx'
|
||||
ok=false
|
||||
fi
|
||||
# test (from $GOPATH) annotation is reported for the first GOPATH entry
|
||||
TEST mention GOPATH in first GOPATH entry
|
||||
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/a/src/foo/quxx \(from \$GOPATH\)$') -ne 1 ] ; then
|
||||
echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)'
|
||||
ok=false
|
||||
fi
|
||||
# but not on the second
|
||||
TEST but not the second entry
|
||||
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/b/src/foo/quxx$') -ne 1 ] ; then
|
||||
echo 'go install foo/quxx expected error: .*testdata/b/src/foo/quxx'
|
||||
ok=false
|
||||
fi
|
||||
# test missing GOPATH is reported
|
||||
TEST missing GOPATH is reported
|
||||
if [ $(GOPATH= ./testgo install 'foo/quxx' 2>&1 | egrep -c '\(\$GOPATH not set\)$') -ne 1 ] ; then
|
||||
echo 'go install foo/quxx expected error: ($GOPATH not set)'
|
||||
ok=false
|
||||
fi
|
||||
|
||||
# issue 4186. go get cannot be used to download packages to $GOROOT
|
||||
# Test that without GOPATH set, go get should fail
|
||||
TEST without GOPATH, go get fails
|
||||
d=$(mktemp -d -t testgoXXX)
|
||||
mkdir -p $d/src/pkg
|
||||
if GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
|
||||
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with $GOPATH unset'
|
||||
ok=false
|
||||
fi
|
||||
rm -rf $d
|
||||
|
||||
# Test that with GOPATH=$GOROOT, go get should fail
|
||||
TEST with GOPATH=GOROOT, go get fails
|
||||
d=$(mktemp -d -t testgoXXX)
|
||||
mkdir -p $d/src/pkg
|
||||
if GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
|
||||
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'
|
||||
ok=false
|
||||
fi
|
||||
rm -rf $d
|
||||
|
||||
TEST ldflags arguments with spaces '(issue 3941)'
|
||||
d=$(mktemp -d -t testgoXXX)
|
||||
cat >$d/main.go<<EOF
|
||||
package main
|
||||
var extern string
|
||||
func main() {
|
||||
println(extern)
|
||||
}
|
||||
EOF
|
||||
./testgo run -ldflags '-X main.extern "hello world"' $d/main.go 2>hello.out
|
||||
if ! grep -q '^hello world' hello.out; then
|
||||
echo "ldflags -X main.extern 'hello world' failed. Output:"
|
||||
cat hello.out
|
||||
ok=false
|
||||
fi
|
||||
rm -rf $d hello.out
|
||||
|
||||
TEST go test -cpuprofile leaves binary behind
|
||||
./testgo test -cpuprofile strings.prof strings || ok=false
|
||||
if [ ! -x strings.test ]; then
|
||||
echo "go test -cpuprofile did not create strings.test"
|
||||
ok=false
|
||||
fi
|
||||
rm -f strings.prof strings.test
|
||||
|
||||
TEST symlinks do not confuse go list '(issue 4568)'
|
||||
old=$(pwd)
|
||||
tmp=$(cd /tmp && pwd -P)
|
||||
d=$(TMPDIR=$tmp mktemp -d -t testgoXXX)
|
||||
mkdir -p $d/src
|
||||
(
|
||||
ln -s $d $d/src/dir1
|
||||
cd $d/src
|
||||
echo package p >dir1/p.go
|
||||
export GOPATH=$d
|
||||
if [ "$($old/testgo list -f '{{.Root}}' dir1)" != "$d" ]; then
|
||||
echo Confused by symlinks.
|
||||
echo "Package in current directory $(pwd) should have Root $d"
|
||||
env|grep WD
|
||||
$old/testgo list -json . dir1
|
||||
touch $d/failed
|
||||
fi
|
||||
)
|
||||
if [ -f $d/failed ]; then
|
||||
ok=false
|
||||
fi
|
||||
rm -rf $d
|
||||
|
||||
TEST 'install with tags (issue 4515)'
|
||||
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
|
||||
mkdir -p $d/src/example/a $d/src/example/b $d/bin
|
||||
cat >$d/src/example/a/main.go <<EOF
|
||||
package main
|
||||
func main() {}
|
||||
EOF
|
||||
cat >$d/src/example/b/main.go <<EOF
|
||||
// +build mytag
|
||||
|
||||
package main
|
||||
func main() {}
|
||||
EOF
|
||||
GOPATH=$d ./testgo install -tags mytag example/a example/b || ok=false
|
||||
if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
|
||||
echo go install example/a example/b did not install binaries
|
||||
ok=false
|
||||
fi
|
||||
rm -f $d/bin/*
|
||||
GOPATH=$d ./testgo install -tags mytag example/... || ok=false
|
||||
if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
|
||||
echo go install example/... did not install binaries
|
||||
ok=false
|
||||
fi
|
||||
rm -f $d/bin/*go
|
||||
export GOPATH=$d
|
||||
if [ "$(./testgo list -tags mytag example/b...)" != "example/b" ]; then
|
||||
echo go list example/b did not find example/b
|
||||
ok=false
|
||||
fi
|
||||
unset GOPATH
|
||||
rm -rf $d
|
||||
|
||||
TEST case collisions '(issue 4773)'
|
||||
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
|
||||
export GOPATH=$d
|
||||
mkdir -p $d/src/example/{a/pkg,a/Pkg,b}
|
||||
cat >$d/src/example/a/a.go <<EOF
|
||||
package p
|
||||
import (
|
||||
_ "example/a/pkg"
|
||||
_ "example/a/Pkg"
|
||||
)
|
||||
EOF
|
||||
cat >$d/src/example/a/pkg/pkg.go <<EOF
|
||||
package pkg
|
||||
EOF
|
||||
cat >$d/src/example/a/Pkg/pkg.go <<EOF
|
||||
package pkg
|
||||
EOF
|
||||
if ./testgo list example/a 2>$d/out; then
|
||||
echo go list example/a should have failed, did not.
|
||||
ok=false
|
||||
elif ! grep "case-insensitive import collision" $d/out >/dev/null; then
|
||||
echo go list example/a did not report import collision.
|
||||
ok=false
|
||||
fi
|
||||
cat >$d/src/example/b/file.go <<EOF
|
||||
package b
|
||||
EOF
|
||||
cat >$d/src/example/b/FILE.go <<EOF
|
||||
package b
|
||||
EOF
|
||||
if [ $(ls $d/src/example/b | wc -l) = 2 ]; then
|
||||
# case-sensitive file system, let directory read find both files
|
||||
args="example/b"
|
||||
else
|
||||
# case-insensitive file system, list files explicitly on command line.
|
||||
args="$d/src/example/b/file.go $d/src/example/b/FILE.go"
|
||||
fi
|
||||
if ./testgo list $args 2>$d/out; then
|
||||
echo go list example/b should have failed, did not.
|
||||
ok=false
|
||||
elif ! grep "case-insensitive file name collision" $d/out >/dev/null; then
|
||||
echo go list example/b did not report file name collision.
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST go get cover
|
||||
./testgo get code.google.com/p/go.tools/cmd/cover || ok=false
|
||||
|
||||
unset GOPATH
|
||||
rm -rf $d
|
||||
|
||||
TEST shadowing logic
|
||||
export GOPATH=$(pwd)/testdata/shadow/root1:$(pwd)/testdata/shadow/root2
|
||||
|
||||
# The math in root1 is not "math" because the standard math is.
|
||||
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/math)
|
||||
if [ "$cdir" != "(_$(pwd)/testdata/shadow/root1/src/math) ($GOROOT/src/pkg/math)" ]; then
|
||||
echo shadowed math is not shadowed: "$cdir"
|
||||
ok=false
|
||||
fi
|
||||
|
||||
# The foo in root1 is "foo".
|
||||
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/foo)
|
||||
if [ "$cdir" != "(foo) ()" ]; then
|
||||
echo unshadowed foo is shadowed: "$cdir"
|
||||
ok=false
|
||||
fi
|
||||
|
||||
# The foo in root2 is not "foo" because the foo in root1 got there first.
|
||||
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root2/src/foo)
|
||||
if [ "$cdir" != "(_$(pwd)/testdata/shadow/root2/src/foo) ($(pwd)/testdata/shadow/root1/src/foo)" ]; then
|
||||
echo shadowed foo is not shadowed: "$cdir"
|
||||
ok=false
|
||||
fi
|
||||
|
||||
# The error for go install should mention the conflicting directory.
|
||||
err=$(! ./testgo install ./testdata/shadow/root2/src/foo 2>&1)
|
||||
if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then
|
||||
echo wrong shadowed install error: "$err"
|
||||
ok=false
|
||||
fi
|
||||
|
||||
# Only succeeds if source order is preserved.
|
||||
TEST source file name order preserved
|
||||
./testgo test testdata/example[12]_test.go || ok=false
|
||||
|
||||
# Check that coverage analysis works at all.
|
||||
# Don't worry about the exact numbers but require not 0.0%.
|
||||
checkcoverage() {
|
||||
if grep '[^0-9]0\.0%' testdata/cover.txt >/dev/null; then
|
||||
echo 'some coverage results are 0.0%'
|
||||
ok=false
|
||||
fi
|
||||
cat testdata/cover.txt
|
||||
rm -f testdata/cover.txt
|
||||
}
|
||||
|
||||
TEST coverage runs
|
||||
./testgo test -short -coverpkg=strings strings regexp >testdata/cover.txt 2>&1 || ok=false
|
||||
./testgo test -short -cover strings math regexp >>testdata/cover.txt 2>&1 || ok=false
|
||||
checkcoverage
|
||||
|
||||
# Check that coverage analysis uses set mode.
|
||||
TEST coverage uses set mode
|
||||
if ./testgo test -short -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
|
||||
if ! grep -q 'mode: set' testdata/cover.out; then
|
||||
ok=false
|
||||
fi
|
||||
checkcoverage
|
||||
else
|
||||
ok=false
|
||||
fi
|
||||
rm -f testdata/cover.out testdata/cover.txt
|
||||
|
||||
TEST coverage uses atomic mode for -race.
|
||||
if ./testgo test -short -race -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
|
||||
if ! grep -q 'mode: atomic' testdata/cover.out; then
|
||||
ok=false
|
||||
fi
|
||||
checkcoverage
|
||||
else
|
||||
ok=false
|
||||
fi
|
||||
rm -f testdata/cover.out
|
||||
|
||||
TEST coverage uses actual setting to override even for -race.
|
||||
if ./testgo test -short -race -cover encoding/binary -covermode=count -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
|
||||
if ! grep -q 'mode: count' testdata/cover.out; then
|
||||
ok=false
|
||||
fi
|
||||
checkcoverage
|
||||
else
|
||||
ok=false
|
||||
fi
|
||||
rm -f testdata/cover.out
|
||||
|
||||
TEST coverage with cgo
|
||||
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
|
||||
./testgo test -short -cover ./testdata/cgocover >testdata/cover.txt 2>&1 || ok=false
|
||||
checkcoverage
|
||||
|
||||
TEST cgo depends on syscall
|
||||
rm -rf $GOROOT/pkg/*_race
|
||||
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
|
||||
export GOPATH=$d
|
||||
mkdir -p $d/src/foo
|
||||
echo '
|
||||
package foo
|
||||
//#include <stdio.h>
|
||||
import "C"
|
||||
' >$d/src/foo/foo.go
|
||||
./testgo build -race foo || ok=false
|
||||
rm -rf $d
|
||||
unset GOPATH
|
||||
|
||||
TEST cgo shows full path names
|
||||
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
|
||||
export GOPATH=$d
|
||||
mkdir -p $d/src/x/y/dirname
|
||||
echo '
|
||||
package foo
|
||||
import "C"
|
||||
func f() {
|
||||
' >$d/src/x/y/dirname/foo.go
|
||||
if ./testgo build x/y/dirname >$d/err 2>&1; then
|
||||
echo build succeeded unexpectedly.
|
||||
ok=false
|
||||
elif ! grep x/y/dirname $d/err >/dev/null; then
|
||||
echo error did not use full path.
|
||||
cat $d/err
|
||||
ok=false
|
||||
fi
|
||||
rm -rf $d
|
||||
unset GOPATH
|
||||
|
||||
TEST 'cgo handles -Wl,$ORIGIN'
|
||||
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
|
||||
export GOPATH=$d
|
||||
mkdir -p $d/src/origin
|
||||
echo '
|
||||
package origin
|
||||
// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
|
||||
// void f(void) {}
|
||||
import "C"
|
||||
|
||||
func f() { C.f() }
|
||||
' >$d/src/origin/origin.go
|
||||
if ! ./testgo build origin; then
|
||||
echo build failed
|
||||
ok=false
|
||||
fi
|
||||
rm -rf $d
|
||||
unset GOPATH
|
||||
|
||||
TEST 'Issue 6480: "go test -c -test.bench=XXX fmt" should not hang'
|
||||
if ! ./testgo test -c -test.bench=XXX fmt; then
|
||||
echo build test failed
|
||||
ok=false
|
||||
fi
|
||||
rm -f fmt.test
|
||||
|
||||
TEST 'Issue 7573: cmd/cgo: undefined reference when linking a C-library using gccgo'
|
||||
d=$(mktemp -d -t testgoXXX)
|
||||
export GOPATH=$d
|
||||
mkdir -p $d/src/cgoref
|
||||
ldflags="-L alibpath -lalib"
|
||||
echo "
|
||||
package main
|
||||
// #cgo LDFLAGS: $ldflags
|
||||
// void f(void) {}
|
||||
import \"C\"
|
||||
|
||||
func main() { C.f() }
|
||||
" >$d/src/cgoref/cgoref.go
|
||||
go_cmds="$(./testgo build -n -compiler gccgo cgoref 2>&1 1>/dev/null)"
|
||||
ldflags_count="$(echo "$go_cmds" | egrep -c "^gccgo.*$(echo $ldflags | sed -e 's/-/\\-/g')" || true)"
|
||||
if [ "$ldflags_count" -lt 1 ]; then
|
||||
echo "No Go-inline "#cgo LDFLAGS:" (\"$ldflags\") passed to gccgo linking stage."
|
||||
ok=false
|
||||
fi
|
||||
rm -rf $d
|
||||
unset ldflags_count
|
||||
unset go_cmds
|
||||
unset ldflags
|
||||
unset GOPATH
|
||||
|
||||
TEST list template can use context function
|
||||
if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
|
||||
echo unable to use context in list template
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST 'Issue 7108: cmd/go: "go test" should fail if package does not build'
|
||||
export GOPATH=$(pwd)/testdata
|
||||
if ./testgo test notest >/dev/null 2>&1; then
|
||||
echo 'go test notest succeeded, but should fail'
|
||||
ok=false
|
||||
fi
|
||||
unset GOPATH
|
||||
|
||||
TEST 'Issue 6844: cmd/go: go test -a foo does not rebuild regexp'
|
||||
if ! ./testgo test -x -a -c testdata/dep_test.go 2>deplist; then
|
||||
echo "go test -x -a -c testdata/dep_test.go failed"
|
||||
ok=false
|
||||
elif ! grep -q regexp deplist; then
|
||||
echo "go test -x -a -c testdata/dep_test.go did not rebuild regexp"
|
||||
ok=false
|
||||
fi
|
||||
rm -f deplist
|
||||
rm -f deps.test
|
||||
|
||||
TEST list template can use context function
|
||||
if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
|
||||
echo unable to use context in list template
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST build -i installs dependencies
|
||||
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
|
||||
export GOPATH=$d
|
||||
mkdir -p $d/src/x/y/foo $d/src/x/y/bar
|
||||
echo '
|
||||
package foo
|
||||
func F() {}
|
||||
' >$d/src/x/y/foo/foo.go
|
||||
echo '
|
||||
package bar
|
||||
import "x/y/foo"
|
||||
func F() { foo.F() }
|
||||
' >$d/src/x/y/bar/bar.go
|
||||
if ! ./testgo build -v -i x/y/bar &> $d/err; then
|
||||
echo build -i failed
|
||||
cat $d/err
|
||||
ok=false
|
||||
elif ! grep x/y/foo $d/err >/dev/null; then
|
||||
echo first build -i did not build x/y/foo
|
||||
cat $d/err
|
||||
ok=false
|
||||
fi
|
||||
if ! ./testgo build -v -i x/y/bar &> $d/err; then
|
||||
echo second build -i failed
|
||||
cat $d/err
|
||||
ok=false
|
||||
elif grep x/y/foo $d/err >/dev/null; then
|
||||
echo second build -i built x/y/foo
|
||||
cat $d/err
|
||||
ok=false
|
||||
fi
|
||||
rm -rf $d
|
||||
unset GOPATH
|
||||
|
||||
TEST 'go build in test-only directory fails with a good error'
|
||||
if ./testgo build ./testdata/testonly 2>testdata/err.out; then
|
||||
echo "go build ./testdata/testonly succeeded, should have failed"
|
||||
ok=false
|
||||
elif ! grep 'no buildable Go' testdata/err.out >/dev/null; then
|
||||
echo "go build ./testdata/testonly produced unexpected error:"
|
||||
cat testdata/err.out
|
||||
ok=false
|
||||
fi
|
||||
rm -f testdata/err.out
|
||||
|
||||
TEST 'go test detects test-only import cycles'
|
||||
export GOPATH=$(pwd)/testdata
|
||||
if ./testgo test -c testcycle/p3 2>testdata/err.out; then
|
||||
echo "go test testcycle/p3 succeeded, should have failed"
|
||||
ok=false
|
||||
elif ! grep 'import cycle not allowed in test' testdata/err.out >/dev/null; then
|
||||
echo "go test testcycle/p3 produced unexpected error:"
|
||||
cat testdata/err.out
|
||||
ok=false
|
||||
fi
|
||||
rm -f testdata/err.out
|
||||
unset GOPATH
|
||||
|
||||
TEST 'go test foo_test.go works'
|
||||
if ! ./testgo test testdata/standalone_test.go; then
|
||||
echo "go test testdata/standalone_test.go failed"
|
||||
ok=false
|
||||
fi
|
||||
|
||||
TEST 'go test xtestonly works'
|
||||
export GOPATH=$(pwd)/testdata
|
||||
./testgo clean -i xtestonly
|
||||
if ! ./testgo test xtestonly >/dev/null; then
|
||||
echo "go test xtestonly failed"
|
||||
ok=false
|
||||
fi
|
||||
unset GOPATH
|
||||
|
||||
|
||||
# clean up
|
||||
if $started; then stop; fi
|
||||
rm -rf testdata/bin testdata/bin1
|
||||
rm -f testgo
|
||||
|
||||
if $allok; then
|
||||
echo PASS
|
||||
else
|
||||
echo FAIL
|
||||
exit 1
|
||||
fi
|
1308
libgo/go/cmd/go/test.go
Normal file
1308
libgo/go/cmd/go/test.go
Normal file
File diff suppressed because it is too large
Load Diff
19
libgo/go/cmd/go/testdata/cgocover/p.go
vendored
Normal file
19
libgo/go/cmd/go/testdata/cgocover/p.go
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
package p
|
||||
|
||||
/*
|
||||
void
|
||||
f(void)
|
||||
{
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
var b bool
|
||||
|
||||
func F() {
|
||||
if b {
|
||||
for {
|
||||
}
|
||||
}
|
||||
C.f()
|
||||
}
|
7
libgo/go/cmd/go/testdata/cgocover/p_test.go
vendored
Normal file
7
libgo/go/cmd/go/testdata/cgocover/p_test.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
package p
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestF(t *testing.T) {
|
||||
F()
|
||||
}
|
7
libgo/go/cmd/go/testdata/dep_test.go
vendored
Normal file
7
libgo/go/cmd/go/testdata/dep_test.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// 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 deps
|
||||
|
||||
import _ "testing"
|
23
libgo/go/cmd/go/testdata/example1_test.go
vendored
Normal file
23
libgo/go/cmd/go/testdata/example1_test.go
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// 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.
|
||||
|
||||
// Make sure that go test runs Example_Z before Example_A, preserving source order.
|
||||
|
||||
package p
|
||||
|
||||
import "fmt"
|
||||
|
||||
var n int
|
||||
|
||||
func Example_Z() {
|
||||
n++
|
||||
fmt.Println(n)
|
||||
// Output: 1
|
||||
}
|
||||
|
||||
func Example_A() {
|
||||
n++
|
||||
fmt.Println(n)
|
||||
// Output: 2
|
||||
}
|
21
libgo/go/cmd/go/testdata/example2_test.go
vendored
Normal file
21
libgo/go/cmd/go/testdata/example2_test.go
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// 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.
|
||||
|
||||
// Make sure that go test runs Example_Y before Example_B, preserving source order.
|
||||
|
||||
package p
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Example_Y() {
|
||||
n++
|
||||
fmt.Println(n)
|
||||
// Output: 3
|
||||
}
|
||||
|
||||
func Example_B() {
|
||||
n++
|
||||
fmt.Println(n)
|
||||
// Output: 4
|
||||
}
|
7
libgo/go/cmd/go/testdata/local/easy.go
vendored
Normal file
7
libgo/go/cmd/go/testdata/local/easy.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "./easysub"
|
||||
|
||||
func main() {
|
||||
easysub.Hello()
|
||||
}
|
7
libgo/go/cmd/go/testdata/local/easysub/easysub.go
vendored
Normal file
7
libgo/go/cmd/go/testdata/local/easysub/easysub.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
package easysub
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Hello() {
|
||||
fmt.Println("easysub.Hello")
|
||||
}
|
9
libgo/go/cmd/go/testdata/local/easysub/main.go
vendored
Normal file
9
libgo/go/cmd/go/testdata/local/easysub/main.go
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import "."
|
||||
|
||||
func main() {
|
||||
easysub.Hello()
|
||||
}
|
7
libgo/go/cmd/go/testdata/local/hard.go
vendored
Normal file
7
libgo/go/cmd/go/testdata/local/hard.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "./sub"
|
||||
|
||||
func main() {
|
||||
sub.Hello()
|
||||
}
|
12
libgo/go/cmd/go/testdata/local/sub/sub.go
vendored
Normal file
12
libgo/go/cmd/go/testdata/local/sub/sub.go
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
package sub
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
subsub "./sub"
|
||||
)
|
||||
|
||||
func Hello() {
|
||||
fmt.Println("sub.Hello")
|
||||
subsub.Hello()
|
||||
}
|
7
libgo/go/cmd/go/testdata/local/sub/sub/subsub.go
vendored
Normal file
7
libgo/go/cmd/go/testdata/local/sub/sub/subsub.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
package subsub
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Hello() {
|
||||
fmt.Println("subsub.Hello")
|
||||
}
|
1
libgo/go/cmd/go/testdata/shadow/root1/src/foo/foo.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/shadow/root1/src/foo/foo.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package foo
|
1
libgo/go/cmd/go/testdata/shadow/root1/src/math/math.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/shadow/root1/src/math/math.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package math
|
1
libgo/go/cmd/go/testdata/shadow/root2/src/foo/foo.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/shadow/root2/src/foo/foo.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package foo
|
1
libgo/go/cmd/go/testdata/src/badpkg/x.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/src/badpkg/x.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
pkg badpkg
|
5
libgo/go/cmd/go/testdata/src/cgotest/m.go
vendored
Normal file
5
libgo/go/cmd/go/testdata/src/cgotest/m.go
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
package cgotest
|
||||
|
||||
import "C"
|
||||
|
||||
var _ C.int
|
5
libgo/go/cmd/go/testdata/src/go-cmd-test/helloworld.go
vendored
Normal file
5
libgo/go/cmd/go/testdata/src/go-cmd-test/helloworld.go
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
println("hello world")
|
||||
}
|
4
libgo/go/cmd/go/testdata/src/main_test/m.go
vendored
Normal file
4
libgo/go/cmd/go/testdata/src/main_test/m.go
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
package main
|
||||
|
||||
func F() {}
|
||||
func main() {}
|
10
libgo/go/cmd/go/testdata/src/main_test/m_test.go
vendored
Normal file
10
libgo/go/cmd/go/testdata/src/main_test/m_test.go
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
. "main_test"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test1(t *testing.T) {
|
||||
F()
|
||||
}
|
6
libgo/go/cmd/go/testdata/src/notest/hello.go
vendored
Normal file
6
libgo/go/cmd/go/testdata/src/notest/hello.go
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
package notest
|
||||
|
||||
func hello() {
|
||||
println("hello world")
|
||||
}
|
||||
Hello world
|
1
libgo/go/cmd/go/testdata/src/syntaxerror/x.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/src/syntaxerror/x.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package p
|
4
libgo/go/cmd/go/testdata/src/syntaxerror/x_test.go
vendored
Normal file
4
libgo/go/cmd/go/testdata/src/syntaxerror/x_test.go
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
package p
|
||||
|
||||
func f() (x.y, z int) {
|
||||
}
|
7
libgo/go/cmd/go/testdata/src/testcycle/p1/p1.go
vendored
Normal file
7
libgo/go/cmd/go/testdata/src/testcycle/p1/p1.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
package p1
|
||||
|
||||
import _ "testcycle/p2"
|
||||
|
||||
func init() {
|
||||
println("p1 init")
|
||||
}
|
6
libgo/go/cmd/go/testdata/src/testcycle/p1/p1_test.go
vendored
Normal file
6
libgo/go/cmd/go/testdata/src/testcycle/p1/p1_test.go
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
package p1
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test(t *testing.T) {
|
||||
}
|
7
libgo/go/cmd/go/testdata/src/testcycle/p2/p2.go
vendored
Normal file
7
libgo/go/cmd/go/testdata/src/testcycle/p2/p2.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
package p2
|
||||
|
||||
import _ "testcycle/p3"
|
||||
|
||||
func init() {
|
||||
println("p2 init")
|
||||
}
|
5
libgo/go/cmd/go/testdata/src/testcycle/p3/p3.go
vendored
Normal file
5
libgo/go/cmd/go/testdata/src/testcycle/p3/p3.go
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
package p3
|
||||
|
||||
func init() {
|
||||
println("p3 init")
|
||||
}
|
10
libgo/go/cmd/go/testdata/src/testcycle/p3/p3_test.go
vendored
Normal file
10
libgo/go/cmd/go/testdata/src/testcycle/p3/p3_test.go
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
package p3
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "testcycle/p1"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
}
|
3
libgo/go/cmd/go/testdata/src/xtestonly/f.go
vendored
Normal file
3
libgo/go/cmd/go/testdata/src/xtestonly/f.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package xtestonly
|
||||
|
||||
func F() int { return 42 }
|
12
libgo/go/cmd/go/testdata/src/xtestonly/f_test.go
vendored
Normal file
12
libgo/go/cmd/go/testdata/src/xtestonly/f_test.go
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
package xtestonly_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"xtestonly"
|
||||
)
|
||||
|
||||
func TestF(t *testing.T) {
|
||||
if x := xtestonly.F(); x != 42 {
|
||||
t.Errorf("f.F() = %d, want 42", x)
|
||||
}
|
||||
}
|
6
libgo/go/cmd/go/testdata/standalone_test.go
vendored
Normal file
6
libgo/go/cmd/go/testdata/standalone_test.go
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
package standalone_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test(t *testing.T) {
|
||||
}
|
3
libgo/go/cmd/go/testdata/testimport/p.go
vendored
Normal file
3
libgo/go/cmd/go/testdata/testimport/p.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package p
|
||||
|
||||
func F() int { return 1 }
|
3
libgo/go/cmd/go/testdata/testimport/p1/p1.go
vendored
Normal file
3
libgo/go/cmd/go/testdata/testimport/p1/p1.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package p1
|
||||
|
||||
func F() int { return 1 }
|
3
libgo/go/cmd/go/testdata/testimport/p2/p2.go
vendored
Normal file
3
libgo/go/cmd/go/testdata/testimport/p2/p2.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package p2
|
||||
|
||||
func F() int { return 1 }
|
13
libgo/go/cmd/go/testdata/testimport/p_test.go
vendored
Normal file
13
libgo/go/cmd/go/testdata/testimport/p_test.go
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
package p
|
||||
|
||||
import (
|
||||
"./p1"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestF(t *testing.T) {
|
||||
if F() != p1.F() {
|
||||
t.Fatal(F())
|
||||
}
|
||||
}
|
15
libgo/go/cmd/go/testdata/testimport/x_test.go
vendored
Normal file
15
libgo/go/cmd/go/testdata/testimport/x_test.go
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
package p_test
|
||||
|
||||
import (
|
||||
. "../testimport"
|
||||
|
||||
"./p2"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestF1(t *testing.T) {
|
||||
if F() != p2.F() {
|
||||
t.Fatal(F())
|
||||
}
|
||||
}
|
1
libgo/go/cmd/go/testdata/testonly/p_test.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/testonly/p_test.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package p
|
318
libgo/go/cmd/go/testflag.go
Normal file
318
libgo/go/cmd/go/testflag.go
Normal file
@ -0,0 +1,318 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The flag handling part of go test is large and distracting.
|
||||
// We can't use the flag package because some of the flags from
|
||||
// our command line are for us, and some are for 6.out, and
|
||||
// some are for both.
|
||||
|
||||
var usageMessage = `Usage of go test:
|
||||
-c=false: compile but do not run the test binary
|
||||
-file=file_test.go: specify file to use for tests;
|
||||
use multiple times for multiple files
|
||||
-p=n: build and test up to n packages in parallel
|
||||
-x=false: print command lines as they are executed
|
||||
|
||||
// These flags can be passed with or without a "test." prefix: -v or -test.v.
|
||||
-bench="": passes -test.bench to test
|
||||
-benchmem=false: print memory allocation statistics for benchmarks
|
||||
-benchtime=1s: passes -test.benchtime to test
|
||||
-cover=false: enable coverage analysis
|
||||
-covermode="set": specifies mode for coverage analysis
|
||||
-coverpkg="": comma-separated list of packages for coverage analysis
|
||||
-coverprofile="": passes -test.coverprofile to test if -cover
|
||||
-cpu="": passes -test.cpu to test
|
||||
-cpuprofile="": passes -test.cpuprofile to test
|
||||
-memprofile="": passes -test.memprofile to test
|
||||
-memprofilerate=0: passes -test.memprofilerate to test
|
||||
-blockprofile="": pases -test.blockprofile to test
|
||||
-blockprofilerate=0: passes -test.blockprofilerate to test
|
||||
-outputdir=$PWD: passes -test.outputdir to test
|
||||
-parallel=0: passes -test.parallel to test
|
||||
-run="": passes -test.run to test
|
||||
-short=false: passes -test.short to test
|
||||
-timeout=0: passes -test.timeout to test
|
||||
-v=false: passes -test.v to test
|
||||
`
|
||||
|
||||
// usage prints a usage message and exits.
|
||||
func testUsage() {
|
||||
fmt.Fprint(os.Stderr, usageMessage)
|
||||
setExitStatus(2)
|
||||
exit()
|
||||
}
|
||||
|
||||
// testFlagSpec defines a flag we know about.
|
||||
type testFlagSpec struct {
|
||||
name string
|
||||
boolVar *bool
|
||||
passToTest bool // pass to Test
|
||||
multiOK bool // OK to have multiple instances
|
||||
present bool // flag has been seen
|
||||
}
|
||||
|
||||
// testFlagDefn is the set of flags we process.
|
||||
var testFlagDefn = []*testFlagSpec{
|
||||
// local.
|
||||
{name: "c", boolVar: &testC},
|
||||
{name: "file", multiOK: true},
|
||||
{name: "cover", boolVar: &testCover},
|
||||
{name: "coverpkg"},
|
||||
|
||||
// build flags.
|
||||
{name: "a", boolVar: &buildA},
|
||||
{name: "n", boolVar: &buildN},
|
||||
{name: "p"},
|
||||
{name: "x", boolVar: &buildX},
|
||||
{name: "i", boolVar: &buildI},
|
||||
{name: "work", boolVar: &buildWork},
|
||||
{name: "ccflags"},
|
||||
{name: "gcflags"},
|
||||
{name: "exec"},
|
||||
{name: "ldflags"},
|
||||
{name: "gccgoflags"},
|
||||
{name: "tags"},
|
||||
{name: "compiler"},
|
||||
{name: "race", boolVar: &buildRace},
|
||||
{name: "installsuffix"},
|
||||
|
||||
// passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
|
||||
{name: "bench", passToTest: true},
|
||||
{name: "benchmem", boolVar: new(bool), passToTest: true},
|
||||
{name: "benchtime", passToTest: true},
|
||||
{name: "covermode"},
|
||||
{name: "coverprofile", passToTest: true},
|
||||
{name: "cpu", passToTest: true},
|
||||
{name: "cpuprofile", passToTest: true},
|
||||
{name: "memprofile", passToTest: true},
|
||||
{name: "memprofilerate", passToTest: true},
|
||||
{name: "blockprofile", passToTest: true},
|
||||
{name: "blockprofilerate", passToTest: true},
|
||||
{name: "outputdir", passToTest: true},
|
||||
{name: "parallel", passToTest: true},
|
||||
{name: "run", passToTest: true},
|
||||
{name: "short", boolVar: new(bool), passToTest: true},
|
||||
{name: "timeout", passToTest: true},
|
||||
{name: "v", boolVar: &testV, passToTest: true},
|
||||
}
|
||||
|
||||
// testFlags processes the command line, grabbing -x and -c, rewriting known flags
|
||||
// to have "test" before them, and reading the command line for the 6.out.
|
||||
// Unfortunately for us, we need to do our own flag processing because go test
|
||||
// grabs some flags but otherwise its command line is just a holding place for
|
||||
// pkg.test's arguments.
|
||||
// We allow known flags both before and after the package name list,
|
||||
// to allow both
|
||||
// go test fmt -custom-flag-for-fmt-test
|
||||
// go test -x math
|
||||
func testFlags(args []string) (packageNames, passToTest []string) {
|
||||
inPkg := false
|
||||
outputDir := ""
|
||||
for i := 0; i < len(args); i++ {
|
||||
if !strings.HasPrefix(args[i], "-") {
|
||||
if !inPkg && packageNames == nil {
|
||||
// First package name we've seen.
|
||||
inPkg = true
|
||||
}
|
||||
if inPkg {
|
||||
packageNames = append(packageNames, args[i])
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if inPkg {
|
||||
// Found an argument beginning with "-"; end of package list.
|
||||
inPkg = false
|
||||
}
|
||||
|
||||
f, value, extraWord := testFlag(args, i)
|
||||
if f == nil {
|
||||
// This is a flag we do not know; we must assume
|
||||
// that any args we see after this might be flag
|
||||
// arguments, not package names.
|
||||
inPkg = false
|
||||
if packageNames == nil {
|
||||
// make non-nil: we have seen the empty package list
|
||||
packageNames = []string{}
|
||||
}
|
||||
passToTest = append(passToTest, args[i])
|
||||
continue
|
||||
}
|
||||
var err error
|
||||
switch f.name {
|
||||
// bool flags.
|
||||
case "a", "c", "i", "n", "x", "v", "race", "cover", "work":
|
||||
setBoolFlag(f.boolVar, value)
|
||||
case "p":
|
||||
setIntFlag(&buildP, value)
|
||||
case "exec":
|
||||
execCmd, err = splitQuotedFields(value)
|
||||
if err != nil {
|
||||
fatalf("invalid flag argument for -%s: %v", f.name, err)
|
||||
}
|
||||
case "ccflags":
|
||||
buildCcflags, err = splitQuotedFields(value)
|
||||
if err != nil {
|
||||
fatalf("invalid flag argument for -%s: %v", f.name, err)
|
||||
}
|
||||
case "gcflags":
|
||||
buildGcflags, err = splitQuotedFields(value)
|
||||
if err != nil {
|
||||
fatalf("invalid flag argument for -%s: %v", f.name, err)
|
||||
}
|
||||
case "ldflags":
|
||||
buildLdflags, err = splitQuotedFields(value)
|
||||
if err != nil {
|
||||
fatalf("invalid flag argument for -%s: %v", f.name, err)
|
||||
}
|
||||
case "gccgoflags":
|
||||
buildGccgoflags, err = splitQuotedFields(value)
|
||||
if err != nil {
|
||||
fatalf("invalid flag argument for -%s: %v", f.name, err)
|
||||
}
|
||||
case "tags":
|
||||
buildContext.BuildTags = strings.Fields(value)
|
||||
case "compiler":
|
||||
buildCompiler{}.Set(value)
|
||||
case "file":
|
||||
testFiles = append(testFiles, value)
|
||||
case "bench":
|
||||
// record that we saw the flag; don't care about the value
|
||||
testBench = true
|
||||
case "timeout":
|
||||
testTimeout = value
|
||||
case "blockprofile", "cpuprofile", "memprofile":
|
||||
testProfile = true
|
||||
testNeedBinary = true
|
||||
case "coverpkg":
|
||||
testCover = true
|
||||
if value == "" {
|
||||
testCoverPaths = nil
|
||||
} else {
|
||||
testCoverPaths = strings.Split(value, ",")
|
||||
}
|
||||
case "coverprofile":
|
||||
testCover = true
|
||||
testProfile = true
|
||||
case "covermode":
|
||||
switch value {
|
||||
case "set", "count", "atomic":
|
||||
testCoverMode = value
|
||||
default:
|
||||
fatalf("invalid flag argument for -cover: %q", value)
|
||||
}
|
||||
testCover = true
|
||||
case "outputdir":
|
||||
outputDir = value
|
||||
}
|
||||
if extraWord {
|
||||
i++
|
||||
}
|
||||
if f.passToTest {
|
||||
passToTest = append(passToTest, "-test."+f.name+"="+value)
|
||||
}
|
||||
}
|
||||
|
||||
if testCoverMode == "" {
|
||||
testCoverMode = "set"
|
||||
if buildRace {
|
||||
// Default coverage mode is atomic when -race is set.
|
||||
testCoverMode = "atomic"
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the test what directory we're running in, so it can write the profiles there.
|
||||
if testProfile && outputDir == "" {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
fatalf("error from os.Getwd: %s", err)
|
||||
}
|
||||
passToTest = append(passToTest, "-test.outputdir", dir)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// testFlag sees if argument i is a known flag and returns its definition, value, and whether it consumed an extra word.
|
||||
func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool) {
|
||||
arg := args[i]
|
||||
if strings.HasPrefix(arg, "--") { // reduce two minuses to one
|
||||
arg = arg[1:]
|
||||
}
|
||||
switch arg {
|
||||
case "-?", "-h", "-help":
|
||||
usage()
|
||||
}
|
||||
if arg == "" || arg[0] != '-' {
|
||||
return
|
||||
}
|
||||
name := arg[1:]
|
||||
// If there's already "test.", drop it for now.
|
||||
name = strings.TrimPrefix(name, "test.")
|
||||
equals := strings.Index(name, "=")
|
||||
if equals >= 0 {
|
||||
value = name[equals+1:]
|
||||
name = name[:equals]
|
||||
}
|
||||
for _, f = range testFlagDefn {
|
||||
if name == f.name {
|
||||
// Booleans are special because they have modes -x, -x=true, -x=false.
|
||||
if f.boolVar != nil {
|
||||
if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag
|
||||
value = "true"
|
||||
} else {
|
||||
// verify it parses
|
||||
setBoolFlag(new(bool), value)
|
||||
}
|
||||
} else { // Non-booleans must have a value.
|
||||
extra = equals < 0
|
||||
if extra {
|
||||
if i+1 >= len(args) {
|
||||
testSyntaxError("missing argument for flag " + f.name)
|
||||
}
|
||||
value = args[i+1]
|
||||
}
|
||||
}
|
||||
if f.present && !f.multiOK {
|
||||
testSyntaxError(f.name + " flag may be set only once")
|
||||
}
|
||||
f.present = true
|
||||
return
|
||||
}
|
||||
}
|
||||
f = nil
|
||||
return
|
||||
}
|
||||
|
||||
// setBoolFlag sets the addressed boolean to the value.
|
||||
func setBoolFlag(flag *bool, value string) {
|
||||
x, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
testSyntaxError("illegal bool flag value " + value)
|
||||
}
|
||||
*flag = x
|
||||
}
|
||||
|
||||
// setIntFlag sets the addressed integer to the value.
|
||||
func setIntFlag(flag *int, value string) {
|
||||
x, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
testSyntaxError("illegal int flag value " + value)
|
||||
}
|
||||
*flag = x
|
||||
}
|
||||
|
||||
func testSyntaxError(msg string) {
|
||||
fmt.Fprintf(os.Stderr, "go test: %s\n", msg)
|
||||
fmt.Fprintf(os.Stderr, `run "go help test" or "go help testflag" for more information`+"\n")
|
||||
os.Exit(2)
|
||||
}
|
156
libgo/go/cmd/go/tool.go
Normal file
156
libgo/go/cmd/go/tool.go
Normal file
@ -0,0 +1,156 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var cmdTool = &Command{
|
||||
Run: runTool,
|
||||
UsageLine: "tool [-n] command [args...]",
|
||||
Short: "run specified go tool",
|
||||
Long: `
|
||||
Tool runs the go tool command identified by the arguments.
|
||||
With no arguments it prints the list of known tools.
|
||||
|
||||
The -n flag causes tool to print the command that would be
|
||||
executed but not execute it.
|
||||
|
||||
For more about each tool command, see 'go tool command -h'.
|
||||
`,
|
||||
}
|
||||
|
||||
var (
|
||||
toolGOOS = runtime.GOOS
|
||||
toolGOARCH = runtime.GOARCH
|
||||
toolIsWindows = toolGOOS == "windows"
|
||||
toolDir = build.ToolDir
|
||||
|
||||
toolN bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmdTool.Flag.BoolVar(&toolN, "n", false, "")
|
||||
}
|
||||
|
||||
const toolWindowsExtension = ".exe"
|
||||
|
||||
func tool(toolName string) string {
|
||||
toolPath := filepath.Join(toolDir, toolName)
|
||||
if toolIsWindows && toolName != "pprof" {
|
||||
toolPath += toolWindowsExtension
|
||||
}
|
||||
// Give a nice message if there is no tool with that name.
|
||||
if _, err := os.Stat(toolPath); err != nil {
|
||||
if isInGoToolsRepo(toolName) {
|
||||
fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get code.google.com/p/go.tools/cmd/%s\n", toolName, toolName)
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
|
||||
}
|
||||
setExitStatus(3)
|
||||
exit()
|
||||
}
|
||||
return toolPath
|
||||
}
|
||||
|
||||
func isInGoToolsRepo(toolName string) bool {
|
||||
switch toolName {
|
||||
case "cover", "vet":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func runTool(cmd *Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
listTools()
|
||||
return
|
||||
}
|
||||
toolName := args[0]
|
||||
// The tool name must be lower-case letters, numbers or underscores.
|
||||
for _, c := range toolName {
|
||||
switch {
|
||||
case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName)
|
||||
setExitStatus(2)
|
||||
return
|
||||
}
|
||||
}
|
||||
toolPath := tool(toolName)
|
||||
if toolPath == "" {
|
||||
return
|
||||
}
|
||||
if toolIsWindows && toolName == "pprof" {
|
||||
args = append([]string{"perl", toolPath}, args[1:]...)
|
||||
var err error
|
||||
toolPath, err = exec.LookPath("perl")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "go tool: perl not found\n")
|
||||
setExitStatus(3)
|
||||
return
|
||||
}
|
||||
}
|
||||
if toolN {
|
||||
fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " "))
|
||||
return
|
||||
}
|
||||
toolCmd := &exec.Cmd{
|
||||
Path: toolPath,
|
||||
Args: args,
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
}
|
||||
err := toolCmd.Run()
|
||||
if err != nil {
|
||||
// Only print about the exit status if the command
|
||||
// didn't even run (not an ExitError) or it didn't exit cleanly
|
||||
// or we're printing command lines too (-x mode).
|
||||
// Assume if command exited cleanly (even with non-zero status)
|
||||
// it printed any messages it wanted to print.
|
||||
if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || buildX {
|
||||
fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err)
|
||||
}
|
||||
setExitStatus(1)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// listTools prints a list of the available tools in the tools directory.
|
||||
func listTools() {
|
||||
f, err := os.Open(toolDir)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err)
|
||||
setExitStatus(2)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
names, err := f.Readdirnames(-1)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err)
|
||||
setExitStatus(2)
|
||||
return
|
||||
}
|
||||
|
||||
sort.Strings(names)
|
||||
for _, name := range names {
|
||||
// Unify presentation by going to lower case.
|
||||
name = strings.ToLower(name)
|
||||
// If it's windows, don't show the .exe suffix.
|
||||
if toolIsWindows && strings.HasSuffix(name, toolWindowsExtension) {
|
||||
name = name[:len(name)-len(toolWindowsExtension)]
|
||||
}
|
||||
fmt.Println(name)
|
||||
}
|
||||
}
|
728
libgo/go/cmd/go/vcs.go
Normal file
728
libgo/go/cmd/go/vcs.go
Normal file
@ -0,0 +1,728 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A vcsCmd describes how to use a version control system
|
||||
// like Mercurial, Git, or Subversion.
|
||||
type vcsCmd struct {
|
||||
name string
|
||||
cmd string // name of binary to invoke command
|
||||
|
||||
createCmd string // command to download a fresh copy of a repository
|
||||
downloadCmd string // command to download updates into an existing repository
|
||||
|
||||
tagCmd []tagCmd // commands to list tags
|
||||
tagLookupCmd []tagCmd // commands to lookup tags before running tagSyncCmd
|
||||
tagSyncCmd string // command to sync to specific tag
|
||||
tagSyncDefault string // command to sync to default tag
|
||||
|
||||
scheme []string
|
||||
pingCmd string
|
||||
}
|
||||
|
||||
// A tagCmd describes a command to list available tags
|
||||
// that can be passed to tagSyncCmd.
|
||||
type tagCmd struct {
|
||||
cmd string // command to list tags
|
||||
pattern string // regexp to extract tags from list
|
||||
}
|
||||
|
||||
// vcsList lists the known version control systems
|
||||
var vcsList = []*vcsCmd{
|
||||
vcsHg,
|
||||
vcsGit,
|
||||
vcsSvn,
|
||||
vcsBzr,
|
||||
}
|
||||
|
||||
// vcsByCmd returns the version control system for the given
|
||||
// command name (hg, git, svn, bzr).
|
||||
func vcsByCmd(cmd string) *vcsCmd {
|
||||
for _, vcs := range vcsList {
|
||||
if vcs.cmd == cmd {
|
||||
return vcs
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// vcsHg describes how to use Mercurial.
|
||||
var vcsHg = &vcsCmd{
|
||||
name: "Mercurial",
|
||||
cmd: "hg",
|
||||
|
||||
createCmd: "clone -U {repo} {dir}",
|
||||
downloadCmd: "pull",
|
||||
|
||||
// We allow both tag and branch names as 'tags'
|
||||
// for selecting a version. This lets people have
|
||||
// a go.release.r60 branch and a go1 branch
|
||||
// and make changes in both, without constantly
|
||||
// editing .hgtags.
|
||||
tagCmd: []tagCmd{
|
||||
{"tags", `^(\S+)`},
|
||||
{"branches", `^(\S+)`},
|
||||
},
|
||||
tagSyncCmd: "update -r {tag}",
|
||||
tagSyncDefault: "update default",
|
||||
|
||||
scheme: []string{"https", "http", "ssh"},
|
||||
pingCmd: "identify {scheme}://{repo}",
|
||||
}
|
||||
|
||||
// vcsGit describes how to use Git.
|
||||
var vcsGit = &vcsCmd{
|
||||
name: "Git",
|
||||
cmd: "git",
|
||||
|
||||
createCmd: "clone {repo} {dir}",
|
||||
downloadCmd: "pull --ff-only",
|
||||
|
||||
tagCmd: []tagCmd{
|
||||
// tags/xxx matches a git tag named xxx
|
||||
// origin/xxx matches a git branch named xxx on the default remote repository
|
||||
{"show-ref", `(?:tags|origin)/(\S+)$`},
|
||||
},
|
||||
tagLookupCmd: []tagCmd{
|
||||
{"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
|
||||
},
|
||||
tagSyncCmd: "checkout {tag}",
|
||||
tagSyncDefault: "checkout master",
|
||||
|
||||
scheme: []string{"git", "https", "http", "git+ssh"},
|
||||
pingCmd: "ls-remote {scheme}://{repo}",
|
||||
}
|
||||
|
||||
// vcsBzr describes how to use Bazaar.
|
||||
var vcsBzr = &vcsCmd{
|
||||
name: "Bazaar",
|
||||
cmd: "bzr",
|
||||
|
||||
createCmd: "branch {repo} {dir}",
|
||||
|
||||
// Without --overwrite bzr will not pull tags that changed.
|
||||
// Replace by --overwrite-tags after http://pad.lv/681792 goes in.
|
||||
downloadCmd: "pull --overwrite",
|
||||
|
||||
tagCmd: []tagCmd{{"tags", `^(\S+)`}},
|
||||
tagSyncCmd: "update -r {tag}",
|
||||
tagSyncDefault: "update -r revno:-1",
|
||||
|
||||
scheme: []string{"https", "http", "bzr", "bzr+ssh"},
|
||||
pingCmd: "info {scheme}://{repo}",
|
||||
}
|
||||
|
||||
// vcsSvn describes how to use Subversion.
|
||||
var vcsSvn = &vcsCmd{
|
||||
name: "Subversion",
|
||||
cmd: "svn",
|
||||
|
||||
createCmd: "checkout {repo} {dir}",
|
||||
downloadCmd: "update",
|
||||
|
||||
// There is no tag command in subversion.
|
||||
// The branch information is all in the path names.
|
||||
|
||||
scheme: []string{"https", "http", "svn", "svn+ssh"},
|
||||
pingCmd: "info {scheme}://{repo}",
|
||||
}
|
||||
|
||||
func (v *vcsCmd) String() string {
|
||||
return v.name
|
||||
}
|
||||
|
||||
// run runs the command line cmd in the given directory.
|
||||
// keyval is a list of key, value pairs. run expands
|
||||
// instances of {key} in cmd into value, but only after
|
||||
// splitting cmd into individual arguments.
|
||||
// If an error occurs, run prints the command line and the
|
||||
// command's combined stdout+stderr to standard error.
|
||||
// Otherwise run discards the command's output.
|
||||
func (v *vcsCmd) run(dir string, cmd string, keyval ...string) error {
|
||||
_, err := v.run1(dir, cmd, keyval, true)
|
||||
return err
|
||||
}
|
||||
|
||||
// runVerboseOnly is like run but only generates error output to standard error in verbose mode.
|
||||
func (v *vcsCmd) runVerboseOnly(dir string, cmd string, keyval ...string) error {
|
||||
_, err := v.run1(dir, cmd, keyval, false)
|
||||
return err
|
||||
}
|
||||
|
||||
// runOutput is like run but returns the output of the command.
|
||||
func (v *vcsCmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) {
|
||||
return v.run1(dir, cmd, keyval, true)
|
||||
}
|
||||
|
||||
// run1 is the generalized implementation of run and runOutput.
|
||||
func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {
|
||||
m := make(map[string]string)
|
||||
for i := 0; i < len(keyval); i += 2 {
|
||||
m[keyval[i]] = keyval[i+1]
|
||||
}
|
||||
args := strings.Fields(cmdline)
|
||||
for i, arg := range args {
|
||||
args[i] = expand(m, arg)
|
||||
}
|
||||
|
||||
_, err := exec.LookPath(v.cmd)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr,
|
||||
"go: missing %s command. See http://golang.org/s/gogetcmd\n",
|
||||
v.name)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd := exec.Command(v.cmd, args...)
|
||||
cmd.Dir = dir
|
||||
cmd.Env = envForDir(cmd.Dir)
|
||||
if buildX {
|
||||
fmt.Printf("cd %s\n", dir)
|
||||
fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
cmd.Stdout = &buf
|
||||
cmd.Stderr = &buf
|
||||
err = cmd.Run()
|
||||
out := buf.Bytes()
|
||||
if err != nil {
|
||||
if verbose || buildV {
|
||||
fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))
|
||||
os.Stderr.Write(out)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ping pings to determine scheme to use.
|
||||
func (v *vcsCmd) ping(scheme, repo string) error {
|
||||
return v.runVerboseOnly(".", v.pingCmd, "scheme", scheme, "repo", repo)
|
||||
}
|
||||
|
||||
// create creates a new copy of repo in dir.
|
||||
// The parent of dir must exist; dir must not.
|
||||
func (v *vcsCmd) create(dir, repo string) error {
|
||||
return v.run(".", v.createCmd, "dir", dir, "repo", repo)
|
||||
}
|
||||
|
||||
// download downloads any new changes for the repo in dir.
|
||||
func (v *vcsCmd) download(dir string) error {
|
||||
if err := v.fixDetachedHead(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
return v.run(dir, v.downloadCmd)
|
||||
}
|
||||
|
||||
// fixDetachedHead switches a Git repository in dir from a detached head to the master branch.
|
||||
// Go versions before 1.2 downloaded Git repositories in an unfortunate way
|
||||
// that resulted in the working tree state being on a detached head.
|
||||
// That meant the repository was not usable for normal Git operations.
|
||||
// Go 1.2 fixed that, but we can't pull into a detached head, so if this is
|
||||
// a Git repository we check for being on a detached head and switch to the
|
||||
// real branch, almost always called "master".
|
||||
// TODO(dsymonds): Consider removing this for Go 1.3.
|
||||
func (v *vcsCmd) fixDetachedHead(dir string) error {
|
||||
if v != vcsGit {
|
||||
return nil
|
||||
}
|
||||
|
||||
// "git symbolic-ref HEAD" succeeds iff we are not on a detached head.
|
||||
if err := v.runVerboseOnly(dir, "symbolic-ref HEAD"); err == nil {
|
||||
// not on a detached head
|
||||
return nil
|
||||
}
|
||||
if buildV {
|
||||
log.Printf("%s on detached head; repairing", dir)
|
||||
}
|
||||
return v.run(dir, "checkout master")
|
||||
}
|
||||
|
||||
// tags returns the list of available tags for the repo in dir.
|
||||
func (v *vcsCmd) tags(dir string) ([]string, error) {
|
||||
var tags []string
|
||||
for _, tc := range v.tagCmd {
|
||||
out, err := v.runOutput(dir, tc.cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
re := regexp.MustCompile(`(?m-s)` + tc.pattern)
|
||||
for _, m := range re.FindAllStringSubmatch(string(out), -1) {
|
||||
tags = append(tags, m[1])
|
||||
}
|
||||
}
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
// tagSync syncs the repo in dir to the named tag,
|
||||
// which either is a tag returned by tags or is v.tagDefault.
|
||||
func (v *vcsCmd) tagSync(dir, tag string) error {
|
||||
if v.tagSyncCmd == "" {
|
||||
return nil
|
||||
}
|
||||
if tag != "" {
|
||||
for _, tc := range v.tagLookupCmd {
|
||||
out, err := v.runOutput(dir, tc.cmd, "tag", tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
re := regexp.MustCompile(`(?m-s)` + tc.pattern)
|
||||
m := re.FindStringSubmatch(string(out))
|
||||
if len(m) > 1 {
|
||||
tag = m[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if tag == "" && v.tagSyncDefault != "" {
|
||||
return v.run(dir, v.tagSyncDefault)
|
||||
}
|
||||
return v.run(dir, v.tagSyncCmd, "tag", tag)
|
||||
}
|
||||
|
||||
// A vcsPath describes how to convert an import path into a
|
||||
// version control system and repository name.
|
||||
type vcsPath struct {
|
||||
prefix string // prefix this description applies to
|
||||
re string // pattern for import path
|
||||
repo string // repository to use (expand with match of re)
|
||||
vcs string // version control system to use (expand with match of re)
|
||||
check func(match map[string]string) error // additional checks
|
||||
ping bool // ping for scheme to use to download repo
|
||||
|
||||
regexp *regexp.Regexp // cached compiled form of re
|
||||
}
|
||||
|
||||
// vcsForDir inspects dir and its parents to determine the
|
||||
// version control system and code repository to use.
|
||||
// On return, root is the import path
|
||||
// corresponding to the root of the repository
|
||||
// (thus root is a prefix of importPath).
|
||||
func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
|
||||
// Clean and double-check that dir is in (a subdirectory of) srcRoot.
|
||||
dir := filepath.Clean(p.Dir)
|
||||
srcRoot := filepath.Clean(p.build.SrcRoot)
|
||||
if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
|
||||
return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
|
||||
}
|
||||
|
||||
origDir := dir
|
||||
for len(dir) > len(srcRoot) {
|
||||
for _, vcs := range vcsList {
|
||||
if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() {
|
||||
return vcs, dir[len(srcRoot)+1:], nil
|
||||
}
|
||||
}
|
||||
|
||||
// Move to parent.
|
||||
ndir := filepath.Dir(dir)
|
||||
if len(ndir) >= len(dir) {
|
||||
// Shouldn't happen, but just in case, stop.
|
||||
break
|
||||
}
|
||||
dir = ndir
|
||||
}
|
||||
|
||||
return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
|
||||
}
|
||||
|
||||
// repoRoot represents a version control system, a repo, and a root of
|
||||
// where to put it on disk.
|
||||
type repoRoot struct {
|
||||
vcs *vcsCmd
|
||||
|
||||
// repo is the repository URL, including scheme
|
||||
repo string
|
||||
|
||||
// root is the import path corresponding to the root of the
|
||||
// repository
|
||||
root string
|
||||
}
|
||||
|
||||
var httpPrefixRE = regexp.MustCompile(`^https?:`)
|
||||
|
||||
// repoRootForImportPath analyzes importPath to determine the
|
||||
// version control system, and code repository to use.
|
||||
func repoRootForImportPath(importPath string) (*repoRoot, error) {
|
||||
rr, err := repoRootForImportPathStatic(importPath, "")
|
||||
if err == errUnknownSite {
|
||||
rr, err = repoRootForImportDynamic(importPath)
|
||||
|
||||
// repoRootForImportDynamic returns error detail
|
||||
// that is irrelevant if the user didn't intend to use a
|
||||
// dynamic import in the first place.
|
||||
// Squelch it.
|
||||
if err != nil {
|
||||
if buildV {
|
||||
log.Printf("import %q: %v", importPath, err)
|
||||
}
|
||||
err = fmt.Errorf("unrecognized import path %q", importPath)
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
|
||||
// Do not allow wildcards in the repo root.
|
||||
rr = nil
|
||||
err = fmt.Errorf("cannot expand ... in %q", importPath)
|
||||
}
|
||||
return rr, err
|
||||
}
|
||||
|
||||
var errUnknownSite = errors.New("dynamic lookup required to find mapping")
|
||||
|
||||
// repoRootForImportPathStatic attempts to map importPath to a
|
||||
// repoRoot using the commonly-used VCS hosting sites in vcsPaths
|
||||
// (github.com/user/dir), or from a fully-qualified importPath already
|
||||
// containing its VCS type (foo.com/repo.git/dir)
|
||||
//
|
||||
// If scheme is non-empty, that scheme is forced.
|
||||
func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
|
||||
// A common error is to use https://packagepath because that's what
|
||||
// hg and git require. Diagnose this helpfully.
|
||||
if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {
|
||||
// The importPath has been cleaned, so has only one slash. The pattern
|
||||
// ignores the slashes; the error message puts them back on the RHS at least.
|
||||
return nil, fmt.Errorf("%q not allowed in import path", importPath[loc[0]:loc[1]]+"//")
|
||||
}
|
||||
for _, srv := range vcsPaths {
|
||||
if !strings.HasPrefix(importPath, srv.prefix) {
|
||||
continue
|
||||
}
|
||||
m := srv.regexp.FindStringSubmatch(importPath)
|
||||
if m == nil {
|
||||
if srv.prefix != "" {
|
||||
return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Build map of named subexpression matches for expand.
|
||||
match := map[string]string{
|
||||
"prefix": srv.prefix,
|
||||
"import": importPath,
|
||||
}
|
||||
for i, name := range srv.regexp.SubexpNames() {
|
||||
if name != "" && match[name] == "" {
|
||||
match[name] = m[i]
|
||||
}
|
||||
}
|
||||
if srv.vcs != "" {
|
||||
match["vcs"] = expand(match, srv.vcs)
|
||||
}
|
||||
if srv.repo != "" {
|
||||
match["repo"] = expand(match, srv.repo)
|
||||
}
|
||||
if srv.check != nil {
|
||||
if err := srv.check(match); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
vcs := vcsByCmd(match["vcs"])
|
||||
if vcs == nil {
|
||||
return nil, fmt.Errorf("unknown version control system %q", match["vcs"])
|
||||
}
|
||||
if srv.ping {
|
||||
if scheme != "" {
|
||||
match["repo"] = scheme + "://" + match["repo"]
|
||||
} else {
|
||||
for _, scheme := range vcs.scheme {
|
||||
if vcs.ping(scheme, match["repo"]) == nil {
|
||||
match["repo"] = scheme + "://" + match["repo"]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rr := &repoRoot{
|
||||
vcs: vcs,
|
||||
repo: match["repo"],
|
||||
root: match["root"],
|
||||
}
|
||||
return rr, nil
|
||||
}
|
||||
return nil, errUnknownSite
|
||||
}
|
||||
|
||||
// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
|
||||
// statically known by repoRootForImportPathStatic.
|
||||
//
|
||||
// This handles "vanity import paths" like "name.tld/pkg/foo".
|
||||
func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
|
||||
slash := strings.Index(importPath, "/")
|
||||
if slash < 0 {
|
||||
return nil, errors.New("import path doesn't contain a slash")
|
||||
}
|
||||
host := importPath[:slash]
|
||||
if !strings.Contains(host, ".") {
|
||||
return nil, errors.New("import path doesn't contain a hostname")
|
||||
}
|
||||
urlStr, body, err := httpsOrHTTP(importPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("http/https fetch: %v", err)
|
||||
}
|
||||
defer body.Close()
|
||||
imports, err := parseMetaGoImports(body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing %s: %v", importPath, err)
|
||||
}
|
||||
metaImport, err := matchGoImport(imports, importPath)
|
||||
if err != nil {
|
||||
if err != errNoMatch {
|
||||
return nil, fmt.Errorf("parse %s: %v", urlStr, err)
|
||||
}
|
||||
return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
|
||||
}
|
||||
if buildV {
|
||||
log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
|
||||
}
|
||||
// If the import was "uni.edu/bob/project", which said the
|
||||
// prefix was "uni.edu" and the RepoRoot was "evilroot.com",
|
||||
// make sure we don't trust Bob and check out evilroot.com to
|
||||
// "uni.edu" yet (possibly overwriting/preempting another
|
||||
// non-evil student). Instead, first verify the root and see
|
||||
// if it matches Bob's claim.
|
||||
if metaImport.Prefix != importPath {
|
||||
if buildV {
|
||||
log.Printf("get %q: verifying non-authoritative meta tag", importPath)
|
||||
}
|
||||
urlStr0 := urlStr
|
||||
urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
|
||||
}
|
||||
imports, err := parseMetaGoImports(body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing %s: %v", importPath, err)
|
||||
}
|
||||
if len(imports) == 0 {
|
||||
return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
|
||||
}
|
||||
metaImport2, err := matchGoImport(imports, importPath)
|
||||
if err != nil || metaImport != metaImport2 {
|
||||
return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.Contains(metaImport.RepoRoot, "://") {
|
||||
return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot)
|
||||
}
|
||||
rr := &repoRoot{
|
||||
vcs: vcsByCmd(metaImport.VCS),
|
||||
repo: metaImport.RepoRoot,
|
||||
root: metaImport.Prefix,
|
||||
}
|
||||
if rr.vcs == nil {
|
||||
return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
|
||||
}
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
// metaImport represents the parsed <meta name="go-import"
|
||||
// content="prefix vcs reporoot" /> tags from HTML files.
|
||||
type metaImport struct {
|
||||
Prefix, VCS, RepoRoot string
|
||||
}
|
||||
|
||||
// errNoMatch is returned from matchGoImport when there's no applicable match.
|
||||
var errNoMatch = errors.New("no import match")
|
||||
|
||||
// matchGoImport returns the metaImport from imports matching importPath.
|
||||
// An error is returned if there are multiple matches.
|
||||
// errNoMatch is returned if none match.
|
||||
func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
|
||||
match := -1
|
||||
for i, im := range imports {
|
||||
if !strings.HasPrefix(importPath, im.Prefix) {
|
||||
continue
|
||||
}
|
||||
if match != -1 {
|
||||
err = fmt.Errorf("multiple meta tags match import path %q", importPath)
|
||||
return
|
||||
}
|
||||
match = i
|
||||
}
|
||||
if match == -1 {
|
||||
err = errNoMatch
|
||||
return
|
||||
}
|
||||
return imports[match], nil
|
||||
}
|
||||
|
||||
// expand rewrites s to replace {k} with match[k] for each key k in match.
|
||||
func expand(match map[string]string, s string) string {
|
||||
for k, v := range match {
|
||||
s = strings.Replace(s, "{"+k+"}", v, -1)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// vcsPaths lists the known vcs paths.
|
||||
var vcsPaths = []*vcsPath{
|
||||
// Google Code - new syntax
|
||||
{
|
||||
prefix: "code.google.com/",
|
||||
re: `^(?P<root>code\.google\.com/p/(?P<project>[a-z0-9\-]+)(\.(?P<subrepo>[a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`,
|
||||
repo: "https://{root}",
|
||||
check: googleCodeVCS,
|
||||
},
|
||||
|
||||
// Google Code - old syntax
|
||||
{
|
||||
re: `^(?P<project>[a-z0-9_\-.]+)\.googlecode\.com/(git|hg|svn)(?P<path>/.*)?$`,
|
||||
check: oldGoogleCode,
|
||||
},
|
||||
|
||||
// Github
|
||||
{
|
||||
prefix: "github.com/",
|
||||
re: `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
|
||||
vcs: "git",
|
||||
repo: "https://{root}",
|
||||
check: noVCSSuffix,
|
||||
},
|
||||
|
||||
// Bitbucket
|
||||
{
|
||||
prefix: "bitbucket.org/",
|
||||
re: `^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
|
||||
repo: "https://{root}",
|
||||
check: bitbucketVCS,
|
||||
},
|
||||
|
||||
// Launchpad
|
||||
{
|
||||
prefix: "launchpad.net/",
|
||||
re: `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
|
||||
vcs: "bzr",
|
||||
repo: "https://{root}",
|
||||
check: launchpadVCS,
|
||||
},
|
||||
|
||||
// General syntax for any server.
|
||||
{
|
||||
re: `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
|
||||
ping: true,
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// fill in cached regexps.
|
||||
// Doing this eagerly discovers invalid regexp syntax
|
||||
// without having to run a command that needs that regexp.
|
||||
for _, srv := range vcsPaths {
|
||||
srv.regexp = regexp.MustCompile(srv.re)
|
||||
}
|
||||
}
|
||||
|
||||
// noVCSSuffix checks that the repository name does not
|
||||
// end in .foo for any version control system foo.
|
||||
// The usual culprit is ".git".
|
||||
func noVCSSuffix(match map[string]string) error {
|
||||
repo := match["repo"]
|
||||
for _, vcs := range vcsList {
|
||||
if strings.HasSuffix(repo, "."+vcs.cmd) {
|
||||
return fmt.Errorf("invalid version control suffix in %s path", match["prefix"])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var googleCheckout = regexp.MustCompile(`id="checkoutcmd">(hg|git|svn)`)
|
||||
|
||||
// googleCodeVCS determines the version control system for
|
||||
// a code.google.com repository, by scraping the project's
|
||||
// /source/checkout page.
|
||||
func googleCodeVCS(match map[string]string) error {
|
||||
if err := noVCSSuffix(match); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := httpGET(expand(match, "https://code.google.com/p/{project}/source/checkout?repo={subrepo}"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m := googleCheckout.FindSubmatch(data); m != nil {
|
||||
if vcs := vcsByCmd(string(m[1])); vcs != nil {
|
||||
// Subversion requires the old URLs.
|
||||
// TODO: Test.
|
||||
if vcs == vcsSvn {
|
||||
if match["subrepo"] != "" {
|
||||
return fmt.Errorf("sub-repositories not supported in Google Code Subversion projects")
|
||||
}
|
||||
match["repo"] = expand(match, "https://{project}.googlecode.com/svn")
|
||||
}
|
||||
match["vcs"] = vcs.cmd
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("unable to detect version control system for code.google.com/ path")
|
||||
}
|
||||
|
||||
// oldGoogleCode is invoked for old-style foo.googlecode.com paths.
|
||||
// It prints an error giving the equivalent new path.
|
||||
func oldGoogleCode(match map[string]string) error {
|
||||
return fmt.Errorf("invalid Google Code import path: use %s instead",
|
||||
expand(match, "code.google.com/p/{project}{path}"))
|
||||
}
|
||||
|
||||
// bitbucketVCS determines the version control system for a
|
||||
// Bitbucket repository, by using the Bitbucket API.
|
||||
func bitbucketVCS(match map[string]string) error {
|
||||
if err := noVCSSuffix(match); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var resp struct {
|
||||
SCM string `json:"scm"`
|
||||
}
|
||||
url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}")
|
||||
data, err := httpGET(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, &resp); err != nil {
|
||||
return fmt.Errorf("decoding %s: %v", url, err)
|
||||
}
|
||||
|
||||
if vcsByCmd(resp.SCM) != nil {
|
||||
match["vcs"] = resp.SCM
|
||||
if resp.SCM == "git" {
|
||||
match["repo"] += ".git"
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
|
||||
}
|
||||
|
||||
// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
|
||||
// "foo" could be a series name registered in Launchpad with its own branch,
|
||||
// and it could also be the name of a directory within the main project
|
||||
// branch one level up.
|
||||
func launchpadVCS(match map[string]string) error {
|
||||
if match["project"] == "" || match["series"] == "" {
|
||||
return nil
|
||||
}
|
||||
_, err := httpGET(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format"))
|
||||
if err != nil {
|
||||
match["root"] = expand(match, "launchpad.net/{project}")
|
||||
match["repo"] = expand(match, "https://{root}")
|
||||
}
|
||||
return nil
|
||||
}
|
25
libgo/go/cmd/go/version.go
Normal file
25
libgo/go/cmd/go/version.go
Normal file
@ -0,0 +1,25 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var cmdVersion = &Command{
|
||||
Run: runVersion,
|
||||
UsageLine: "version",
|
||||
Short: "print Go version",
|
||||
Long: `Version prints the Go version, as reported by runtime.Version.`,
|
||||
}
|
||||
|
||||
func runVersion(cmd *Command, args []string) {
|
||||
if len(args) != 0 {
|
||||
cmd.Usage()
|
||||
}
|
||||
|
||||
fmt.Printf("go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
}
|
37
libgo/go/cmd/go/vet.go
Normal file
37
libgo/go/cmd/go/vet.go
Normal file
@ -0,0 +1,37 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
func init() {
|
||||
addBuildFlagsNX(cmdVet)
|
||||
}
|
||||
|
||||
var cmdVet = &Command{
|
||||
Run: runVet,
|
||||
UsageLine: "vet [-n] [-x] [packages]",
|
||||
Short: "run go tool vet on packages",
|
||||
Long: `
|
||||
Vet runs the Go vet command on the packages named by the import paths.
|
||||
|
||||
For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'.
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
To run the vet tool with specific options, run 'go tool vet'.
|
||||
|
||||
The -n flag prints commands that would be executed.
|
||||
The -x flag prints commands as they are executed.
|
||||
|
||||
See also: go fmt, go fix.
|
||||
`,
|
||||
}
|
||||
|
||||
func runVet(cmd *Command, args []string) {
|
||||
for _, pkg := range packages(args) {
|
||||
// Use pkg.gofiles instead of pkg.Dir so that
|
||||
// the command only applies to this package,
|
||||
// not to packages in subdirectories.
|
||||
run(tool("vet"), relPaths(stringList(pkg.gofiles, pkg.sfiles)))
|
||||
}
|
||||
}
|
93
libgo/go/cmd/gofmt/doc.go
Normal file
93
libgo/go/cmd/gofmt/doc.go
Normal file
@ -0,0 +1,93 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
Gofmt formats Go programs.
|
||||
It uses tabs (width = 8) for indentation and blanks for alignment.
|
||||
|
||||
Without an explicit path, it processes the standard input. Given a file,
|
||||
it operates on that file; given a directory, it operates on all .go files in
|
||||
that directory, recursively. (Files starting with a period are ignored.)
|
||||
By default, gofmt prints the reformatted sources to standard output.
|
||||
|
||||
Usage:
|
||||
gofmt [flags] [path ...]
|
||||
|
||||
The flags are:
|
||||
-d
|
||||
Do not print reformatted sources to standard output.
|
||||
If a file's formatting is different than gofmt's, print diffs
|
||||
to standard output.
|
||||
-e
|
||||
Print all (including spurious) errors.
|
||||
-l
|
||||
Do not print reformatted sources to standard output.
|
||||
If a file's formatting is different from gofmt's, print its name
|
||||
to standard output.
|
||||
-r rule
|
||||
Apply the rewrite rule to the source before reformatting.
|
||||
-s
|
||||
Try to simplify code (after applying the rewrite rule, if any).
|
||||
-w
|
||||
Do not print reformatted sources to standard output.
|
||||
If a file's formatting is different from gofmt's, overwrite it
|
||||
with gofmt's version.
|
||||
|
||||
Debugging support:
|
||||
-cpuprofile filename
|
||||
Write cpu profile to the specified file.
|
||||
|
||||
|
||||
The rewrite rule specified with the -r flag must be a string of the form:
|
||||
|
||||
pattern -> replacement
|
||||
|
||||
Both pattern and replacement must be valid Go expressions.
|
||||
In the pattern, single-character lowercase identifiers serve as
|
||||
wildcards matching arbitrary sub-expressions; those expressions
|
||||
will be substituted for the same identifiers in the replacement.
|
||||
|
||||
When gofmt reads from standard input, it accepts either a full Go program
|
||||
or a program fragment. A program fragment must be a syntactically
|
||||
valid declaration list, statement list, or expression. When formatting
|
||||
such a fragment, gofmt preserves leading indentation as well as leading
|
||||
and trailing spaces, so that individual sections of a Go program can be
|
||||
formatted by piping them through gofmt.
|
||||
|
||||
Examples
|
||||
|
||||
To check files for unnecessary parentheses:
|
||||
|
||||
gofmt -r '(a) -> a' -l *.go
|
||||
|
||||
To remove the parentheses:
|
||||
|
||||
gofmt -r '(a) -> a' -w *.go
|
||||
|
||||
To convert the package tree from explicit slice upper bounds to implicit ones:
|
||||
|
||||
gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src/pkg
|
||||
|
||||
The simplify command
|
||||
|
||||
When invoked with -s gofmt will make the following source transformations where possible.
|
||||
|
||||
An array, slice, or map composite literal of the form:
|
||||
[]T{T{}, T{}}
|
||||
will be simplified to:
|
||||
[]T{{}, {}}
|
||||
|
||||
A slice expression of the form:
|
||||
s[a:len(s)]
|
||||
will be simplified to:
|
||||
s[a:]
|
||||
|
||||
A range of the form:
|
||||
for x, _ = range v {...}
|
||||
will be simplified to:
|
||||
for x = range v {...}
|
||||
*/
|
||||
package main
|
||||
|
||||
// BUG(rsc): The implementation of -r is a bit slow.
|
344
libgo/go/cmd/gofmt/gofmt.go
Normal file
344
libgo/go/cmd/gofmt/gofmt.go
Normal file
@ -0,0 +1,344 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/printer"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// main operation modes
|
||||
list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
|
||||
write = flag.Bool("w", false, "write result to (source) file instead of stdout")
|
||||
rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')")
|
||||
simplifyAST = flag.Bool("s", false, "simplify code")
|
||||
doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
|
||||
allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)")
|
||||
|
||||
// debugging
|
||||
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
|
||||
)
|
||||
|
||||
const (
|
||||
tabWidth = 8
|
||||
printerMode = printer.UseSpaces | printer.TabIndent
|
||||
)
|
||||
|
||||
var (
|
||||
fileSet = token.NewFileSet() // per process FileSet
|
||||
exitCode = 0
|
||||
rewrite func(*ast.File) *ast.File
|
||||
parserMode parser.Mode
|
||||
)
|
||||
|
||||
func report(err error) {
|
||||
scanner.PrintError(os.Stderr, err)
|
||||
exitCode = 2
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
func initParserMode() {
|
||||
parserMode = parser.ParseComments
|
||||
if *allErrors {
|
||||
parserMode |= parser.AllErrors
|
||||
}
|
||||
}
|
||||
|
||||
func isGoFile(f os.FileInfo) bool {
|
||||
// ignore non-Go files
|
||||
name := f.Name()
|
||||
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
|
||||
}
|
||||
|
||||
// If in == nil, the source is the contents of the file with the given filename.
|
||||
func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
|
||||
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
|
||||
}
|
||||
|
||||
file, adjust, err := parse(fileSet, filename, src, stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rewrite != nil {
|
||||
if adjust == nil {
|
||||
file = rewrite(file)
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n")
|
||||
}
|
||||
}
|
||||
|
||||
ast.SortImports(fileSet, file)
|
||||
|
||||
if *simplifyAST {
|
||||
simplify(file)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fileSet, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res := buf.Bytes()
|
||||
if adjust != nil {
|
||||
res = adjust(src, res)
|
||||
}
|
||||
|
||||
if !bytes.Equal(src, res) {
|
||||
// formatting has changed
|
||||
if *list {
|
||||
fmt.Fprintln(out, filename)
|
||||
}
|
||||
if *write {
|
||||
err = ioutil.WriteFile(filename, res, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if *doDiff {
|
||||
data, err := diff(src, res)
|
||||
if err != nil {
|
||||
return fmt.Errorf("computing diff: %s", err)
|
||||
}
|
||||
fmt.Printf("diff %s gofmt/%s\n", filename, 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, false)
|
||||
}
|
||||
if err != nil {
|
||||
report(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func walkDir(path string) {
|
||||
filepath.Walk(path, visitFile)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// call gofmtMain in a separate function
|
||||
// so that it can use defer and have them
|
||||
// run before the exit.
|
||||
gofmtMain()
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
func gofmtMain() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
|
||||
if *cpuprofile != "" {
|
||||
f, err := os.Create(*cpuprofile)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err)
|
||||
exitCode = 2
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
pprof.StartCPUProfile(f)
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
|
||||
initParserMode()
|
||||
initRewrite()
|
||||
|
||||
if flag.NArg() == 0 {
|
||||
if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
|
||||
report(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < flag.NArg(); i++ {
|
||||
path := flag.Arg(i)
|
||||
switch dir, err := os.Stat(path); {
|
||||
case err != nil:
|
||||
report(err)
|
||||
case dir.IsDir():
|
||||
walkDir(path)
|
||||
default:
|
||||
if err := processFile(path, nil, os.Stdout, false); err != nil {
|
||||
report(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func diff(b1, b2 []byte) (data []byte, err error) {
|
||||
f1, err := ioutil.TempFile("", "gofmt")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer os.Remove(f1.Name())
|
||||
defer f1.Close()
|
||||
|
||||
f2, err := ioutil.TempFile("", "gofmt")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer os.Remove(f2.Name())
|
||||
defer f2.Close()
|
||||
|
||||
f1.Write(b1)
|
||||
f2.Write(b2)
|
||||
|
||||
data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).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.
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// parse parses src, which was read from filename,
|
||||
// as a Go source file or statement list.
|
||||
func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.File, func(orig, src []byte) []byte, error) {
|
||||
// Try as whole source file.
|
||||
file, err := parser.ParseFile(fset, filename, src, parserMode)
|
||||
if err == nil {
|
||||
return file, nil, nil
|
||||
}
|
||||
// If the error is that the source file didn't begin with a
|
||||
// package line and this is standard input, fall through to
|
||||
// try as a source fragment. Stop and return on any other error.
|
||||
if !stdin || !strings.Contains(err.Error(), "expected 'package'") {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// If this is a declaration list, make it a source file
|
||||
// by inserting a package clause.
|
||||
// Insert using a ;, not a newline, so that the line numbers
|
||||
// in psrc match the ones in src.
|
||||
psrc := append([]byte("package p;"), src...)
|
||||
file, err = parser.ParseFile(fset, filename, psrc, parserMode)
|
||||
if err == nil {
|
||||
adjust := func(orig, src []byte) []byte {
|
||||
// Remove the package clause.
|
||||
// Gofmt has turned the ; into a \n.
|
||||
src = src[len("package p\n"):]
|
||||
return matchSpace(orig, src)
|
||||
}
|
||||
return file, adjust, nil
|
||||
}
|
||||
// If the error is that the source file didn't begin with a
|
||||
// declaration, fall through to try as a statement list.
|
||||
// Stop and return on any other error.
|
||||
if !strings.Contains(err.Error(), "expected declaration") {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// If this is a statement list, make it a source file
|
||||
// by inserting a package clause and turning the list
|
||||
// into a function body. This handles expressions too.
|
||||
// Insert using a ;, not a newline, so that the line numbers
|
||||
// in fsrc match the ones in src.
|
||||
fsrc := append(append([]byte("package p; func _() {"), src...), '}')
|
||||
file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
|
||||
if err == nil {
|
||||
adjust := func(orig, src []byte) []byte {
|
||||
// Remove the wrapping.
|
||||
// Gofmt has turned the ; into a \n\n.
|
||||
src = src[len("package p\n\nfunc _() {"):]
|
||||
src = src[:len(src)-len("}\n")]
|
||||
// Gofmt has also indented the function body one level.
|
||||
// Remove that indent.
|
||||
src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1)
|
||||
return matchSpace(orig, src)
|
||||
}
|
||||
return file, adjust, nil
|
||||
}
|
||||
|
||||
// Failed, and out of options.
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
func cutSpace(b []byte) (before, middle, after []byte) {
|
||||
i := 0
|
||||
for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') {
|
||||
i++
|
||||
}
|
||||
j := len(b)
|
||||
for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') {
|
||||
j--
|
||||
}
|
||||
if i <= j {
|
||||
return b[:i], b[i:j], b[j:]
|
||||
}
|
||||
return nil, nil, b[j:]
|
||||
}
|
||||
|
||||
// matchSpace reformats src to use the same space context as orig.
|
||||
// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src.
|
||||
// 2) matchSpace copies the indentation of the first non-blank line in orig
|
||||
// to every non-blank line in src.
|
||||
// 3) matchSpace copies the trailing space from orig and uses it in place
|
||||
// of src's trailing space.
|
||||
func matchSpace(orig []byte, src []byte) []byte {
|
||||
before, _, after := cutSpace(orig)
|
||||
i := bytes.LastIndex(before, []byte{'\n'})
|
||||
before, indent := before[:i+1], before[i+1:]
|
||||
|
||||
_, src, _ = cutSpace(src)
|
||||
|
||||
var b bytes.Buffer
|
||||
b.Write(before)
|
||||
for len(src) > 0 {
|
||||
line := src
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, src = line[:i+1], line[i+1:]
|
||||
} else {
|
||||
src = nil
|
||||
}
|
||||
if len(line) > 0 && line[0] != '\n' { // not blank
|
||||
b.Write(indent)
|
||||
}
|
||||
b.Write(line)
|
||||
}
|
||||
b.Write(after)
|
||||
return b.Bytes()
|
||||
}
|
134
libgo/go/cmd/gofmt/gofmt_test.go
Normal file
134
libgo/go/cmd/gofmt/gofmt_test.go
Normal file
@ -0,0 +1,134 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func runTest(t *testing.T, in, out, flags string) {
|
||||
// process flags
|
||||
*simplifyAST = false
|
||||
*rewriteRule = ""
|
||||
stdin := false
|
||||
for _, flag := range strings.Split(flags, " ") {
|
||||
elts := strings.SplitN(flag, "=", 2)
|
||||
name := elts[0]
|
||||
value := ""
|
||||
if len(elts) == 2 {
|
||||
value = elts[1]
|
||||
}
|
||||
switch name {
|
||||
case "":
|
||||
// no flags
|
||||
case "-r":
|
||||
*rewriteRule = value
|
||||
case "-s":
|
||||
*simplifyAST = true
|
||||
case "-stdin":
|
||||
// fake flag - pretend input is from stdin
|
||||
stdin = true
|
||||
default:
|
||||
t.Errorf("unrecognized flag name: %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
initParserMode()
|
||||
initRewrite()
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := processFile(in, nil, &buf, stdin)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
expected, err := ioutil.ReadFile(out)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if got := buf.Bytes(); !bytes.Equal(got, expected) {
|
||||
t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
|
||||
d, err := diff(expected, got)
|
||||
if err == nil {
|
||||
t.Errorf("%s", d)
|
||||
}
|
||||
if err := ioutil.WriteFile(in+".gofmt", got, 0666); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
in, flags string
|
||||
}{
|
||||
{"gofmt.go", ""},
|
||||
{"gofmt_test.go", ""},
|
||||
{"testdata/composites.input", "-s"},
|
||||
{"testdata/slices1.input", "-s"},
|
||||
{"testdata/slices2.input", "-s"},
|
||||
{"testdata/old.input", ""},
|
||||
{"testdata/rewrite1.input", "-r=Foo->Bar"},
|
||||
{"testdata/rewrite2.input", "-r=int->bool"},
|
||||
{"testdata/rewrite3.input", "-r=x->x"},
|
||||
{"testdata/rewrite4.input", "-r=(x)->x"},
|
||||
{"testdata/rewrite5.input", "-r=x+x->2*x"},
|
||||
{"testdata/rewrite6.input", "-r=fun(x)->Fun(x)"},
|
||||
{"testdata/rewrite7.input", "-r=fun(x...)->Fun(x)"},
|
||||
{"testdata/rewrite8.input", "-r=interface{}->int"},
|
||||
{"testdata/stdin*.input", "-stdin"},
|
||||
{"testdata/comments.input", ""},
|
||||
{"testdata/import.input", ""},
|
||||
{"testdata/crlf.input", ""}, // test case for issue 3961; see also TestCRLF
|
||||
{"testdata/typeswitch.input", ""}, // test case for issue 4470
|
||||
}
|
||||
|
||||
func TestRewrite(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
match, err := filepath.Glob(test.in)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
for _, in := range match {
|
||||
out := in
|
||||
if strings.HasSuffix(in, ".input") {
|
||||
out = in[:len(in)-len(".input")] + ".golden"
|
||||
}
|
||||
runTest(t, in, out, test.flags)
|
||||
if in != out {
|
||||
// Check idempotence.
|
||||
runTest(t, out, out, test.flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCRLF(t *testing.T) {
|
||||
const input = "testdata/crlf.input" // must contain CR/LF's
|
||||
const golden = "testdata/crlf.golden" // must not contain any CR's
|
||||
|
||||
data, err := ioutil.ReadFile(input)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if bytes.Index(data, []byte("\r\n")) < 0 {
|
||||
t.Errorf("%s contains no CR/LF's", input)
|
||||
}
|
||||
|
||||
data, err = ioutil.ReadFile(golden)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if bytes.Index(data, []byte("\r")) >= 0 {
|
||||
t.Errorf("%s contains CR's", golden)
|
||||
}
|
||||
}
|
159
libgo/go/cmd/gofmt/long_test.go
Normal file
159
libgo/go/cmd/gofmt/long_test.go
Normal file
@ -0,0 +1,159 @@
|
||||
// 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 test applies gofmt to all Go files under -root.
|
||||
// To test specific files provide a list of comma-separated
|
||||
// filenames via the -files flag: go test -files=gofmt.go .
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
root = flag.String("root", runtime.GOROOT(), "test root directory")
|
||||
files = flag.String("files", "", "comma-separated list of files to test")
|
||||
ngo = flag.Int("n", runtime.NumCPU(), "number of goroutines used")
|
||||
verbose = flag.Bool("verbose", false, "verbose mode")
|
||||
nfiles int // number of files processed
|
||||
)
|
||||
|
||||
func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
|
||||
f, _, err := parse(fset, filename, src.Bytes(), false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ast.SortImports(fset, f)
|
||||
src.Reset()
|
||||
return (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(src, fset, f)
|
||||
}
|
||||
|
||||
func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
|
||||
// open file
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// read file
|
||||
b1.Reset()
|
||||
_, err = io.Copy(b1, f)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// exclude files w/ syntax errors (typically test cases)
|
||||
fset := token.NewFileSet()
|
||||
if _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
|
||||
if *verbose {
|
||||
fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// gofmt file
|
||||
if err = gofmt(fset, filename, b1); err != nil {
|
||||
t.Errorf("1st gofmt failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// make a copy of the result
|
||||
b2.Reset()
|
||||
b2.Write(b1.Bytes())
|
||||
|
||||
// gofmt result again
|
||||
if err = gofmt(fset, filename, b2); err != nil {
|
||||
t.Errorf("2nd gofmt failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// the first and 2nd result should be identical
|
||||
if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
|
||||
t.Errorf("gofmt %s not idempotent", filename)
|
||||
}
|
||||
}
|
||||
|
||||
func testFiles(t *testing.T, filenames <-chan string, done chan<- int) {
|
||||
b1 := new(bytes.Buffer)
|
||||
b2 := new(bytes.Buffer)
|
||||
for filename := range filenames {
|
||||
testFile(t, b1, b2, filename)
|
||||
}
|
||||
done <- 0
|
||||
}
|
||||
|
||||
func genFilenames(t *testing.T, filenames chan<- string) {
|
||||
defer close(filenames)
|
||||
|
||||
handleFile := func(filename string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return nil
|
||||
}
|
||||
if isGoFile(fi) {
|
||||
filenames <- filename
|
||||
nfiles++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// test Go files provided via -files, if any
|
||||
if *files != "" {
|
||||
for _, filename := range strings.Split(*files, ",") {
|
||||
fi, err := os.Stat(filename)
|
||||
handleFile(filename, fi, err)
|
||||
}
|
||||
return // ignore files under -root
|
||||
}
|
||||
|
||||
// otherwise, test all Go files under *root
|
||||
filepath.Walk(*root, handleFile)
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
if *ngo < 1 {
|
||||
*ngo = 1 // make sure test is run
|
||||
}
|
||||
if *verbose {
|
||||
fmt.Printf("running test using %d goroutines\n", *ngo)
|
||||
}
|
||||
|
||||
// generate filenames
|
||||
filenames := make(chan string, 32)
|
||||
go genFilenames(t, filenames)
|
||||
|
||||
// launch test goroutines
|
||||
done := make(chan int)
|
||||
for i := 0; i < *ngo; i++ {
|
||||
go testFiles(t, filenames, done)
|
||||
}
|
||||
|
||||
// wait for all test goroutines to complete
|
||||
for i := 0; i < *ngo; i++ {
|
||||
<-done
|
||||
}
|
||||
|
||||
if *verbose {
|
||||
fmt.Printf("processed %d files\n", nfiles)
|
||||
}
|
||||
}
|
306
libgo/go/cmd/gofmt/rewrite.go
Normal file
306
libgo/go/cmd/gofmt/rewrite.go
Normal file
@ -0,0 +1,306 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func initRewrite() {
|
||||
if *rewriteRule == "" {
|
||||
rewrite = nil // disable any previous rewrite
|
||||
return
|
||||
}
|
||||
f := strings.Split(*rewriteRule, "->")
|
||||
if len(f) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
pattern := parseExpr(f[0], "pattern")
|
||||
replace := parseExpr(f[1], "replacement")
|
||||
rewrite = func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
|
||||
}
|
||||
|
||||
// parseExpr parses s as an expression.
|
||||
// It might make sense to expand this to allow statement patterns,
|
||||
// but there are problems with preserving formatting and also
|
||||
// with what a wildcard for a statement looks like.
|
||||
func parseExpr(s, what string) ast.Expr {
|
||||
x, err := parser.ParseExpr(s)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "parsing %s %s at %s\n", what, s, err)
|
||||
os.Exit(2)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Keep this function for debugging.
|
||||
/*
|
||||
func dump(msg string, val reflect.Value) {
|
||||
fmt.Printf("%s:\n", msg)
|
||||
ast.Print(fileSet, val.Interface())
|
||||
fmt.Println()
|
||||
}
|
||||
*/
|
||||
|
||||
// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
|
||||
func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
|
||||
cmap := ast.NewCommentMap(fileSet, p, p.Comments)
|
||||
m := make(map[string]reflect.Value)
|
||||
pat := reflect.ValueOf(pattern)
|
||||
repl := reflect.ValueOf(replace)
|
||||
|
||||
var rewriteVal func(val reflect.Value) reflect.Value
|
||||
rewriteVal = func(val reflect.Value) reflect.Value {
|
||||
// don't bother if val is invalid to start with
|
||||
if !val.IsValid() {
|
||||
return reflect.Value{}
|
||||
}
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
}
|
||||
val = apply(rewriteVal, val)
|
||||
if match(m, pat, val) {
|
||||
val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
r := apply(rewriteVal, reflect.ValueOf(p)).Interface().(*ast.File)
|
||||
r.Comments = cmap.Filter(r).Comments() // recreate comments list
|
||||
return r
|
||||
}
|
||||
|
||||
// set is a wrapper for x.Set(y); it protects the caller from panics if x cannot be changed to y.
|
||||
func set(x, y reflect.Value) {
|
||||
// don't bother if x cannot be set or y is invalid
|
||||
if !x.CanSet() || !y.IsValid() {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if x := recover(); x != nil {
|
||||
if s, ok := x.(string); ok &&
|
||||
(strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) {
|
||||
// x cannot be set to y - ignore this rewrite
|
||||
return
|
||||
}
|
||||
panic(x)
|
||||
}
|
||||
}()
|
||||
x.Set(y)
|
||||
}
|
||||
|
||||
// Values/types for special cases.
|
||||
var (
|
||||
objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
|
||||
scopePtrNil = reflect.ValueOf((*ast.Scope)(nil))
|
||||
|
||||
identType = reflect.TypeOf((*ast.Ident)(nil))
|
||||
objectPtrType = reflect.TypeOf((*ast.Object)(nil))
|
||||
positionType = reflect.TypeOf(token.NoPos)
|
||||
callExprType = reflect.TypeOf((*ast.CallExpr)(nil))
|
||||
scopePtrType = reflect.TypeOf((*ast.Scope)(nil))
|
||||
)
|
||||
|
||||
// apply replaces each AST field x in val with f(x), returning val.
|
||||
// To avoid extra conversions, f operates on the reflect.Value form.
|
||||
func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
|
||||
if !val.IsValid() {
|
||||
return reflect.Value{}
|
||||
}
|
||||
|
||||
// *ast.Objects introduce cycles and are likely incorrect after
|
||||
// rewrite; don't follow them but replace with nil instead
|
||||
if val.Type() == objectPtrType {
|
||||
return objectPtrNil
|
||||
}
|
||||
|
||||
// similarly for scopes: they are likely incorrect after a rewrite;
|
||||
// replace them with nil
|
||||
if val.Type() == scopePtrType {
|
||||
return scopePtrNil
|
||||
}
|
||||
|
||||
switch v := reflect.Indirect(val); v.Kind() {
|
||||
case reflect.Slice:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
e := v.Index(i)
|
||||
set(e, f(e))
|
||||
}
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
e := v.Field(i)
|
||||
set(e, f(e))
|
||||
}
|
||||
case reflect.Interface:
|
||||
e := v.Elem()
|
||||
set(v, f(e))
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func isWildcard(s string) bool {
|
||||
rune, size := utf8.DecodeRuneInString(s)
|
||||
return size == len(s) && unicode.IsLower(rune)
|
||||
}
|
||||
|
||||
// match returns true if pattern matches val,
|
||||
// recording wildcard submatches in m.
|
||||
// If m == nil, match checks whether pattern == val.
|
||||
func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
|
||||
// Wildcard matches any expression. If it appears multiple
|
||||
// times in the pattern, it must match the same expression
|
||||
// each time.
|
||||
if m != nil && pattern.IsValid() && pattern.Type() == identType {
|
||||
name := pattern.Interface().(*ast.Ident).Name
|
||||
if isWildcard(name) && val.IsValid() {
|
||||
// wildcards only match valid (non-nil) expressions.
|
||||
if _, ok := val.Interface().(ast.Expr); ok && !val.IsNil() {
|
||||
if old, ok := m[name]; ok {
|
||||
return match(nil, old, val)
|
||||
}
|
||||
m[name] = val
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, pattern and val must match recursively.
|
||||
if !pattern.IsValid() || !val.IsValid() {
|
||||
return !pattern.IsValid() && !val.IsValid()
|
||||
}
|
||||
if pattern.Type() != val.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Special cases.
|
||||
switch pattern.Type() {
|
||||
case identType:
|
||||
// For identifiers, only the names need to match
|
||||
// (and none of the other *ast.Object information).
|
||||
// This is a common case, handle it all here instead
|
||||
// of recursing down any further via reflection.
|
||||
p := pattern.Interface().(*ast.Ident)
|
||||
v := val.Interface().(*ast.Ident)
|
||||
return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
|
||||
case objectPtrType, positionType:
|
||||
// object pointers and token positions always match
|
||||
return true
|
||||
case callExprType:
|
||||
// For calls, the Ellipsis fields (token.Position) must
|
||||
// match since that is how f(x) and f(x...) are different.
|
||||
// Check them here but fall through for the remaining fields.
|
||||
p := pattern.Interface().(*ast.CallExpr)
|
||||
v := val.Interface().(*ast.CallExpr)
|
||||
if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
p := reflect.Indirect(pattern)
|
||||
v := reflect.Indirect(val)
|
||||
if !p.IsValid() || !v.IsValid() {
|
||||
return !p.IsValid() && !v.IsValid()
|
||||
}
|
||||
|
||||
switch p.Kind() {
|
||||
case reflect.Slice:
|
||||
if p.Len() != v.Len() {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < p.Len(); i++ {
|
||||
if !match(m, p.Index(i), v.Index(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
case reflect.Struct:
|
||||
if p.NumField() != v.NumField() {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < p.NumField(); i++ {
|
||||
if !match(m, p.Field(i), v.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
case reflect.Interface:
|
||||
return match(m, p.Elem(), v.Elem())
|
||||
}
|
||||
|
||||
// Handle token integers, etc.
|
||||
return p.Interface() == v.Interface()
|
||||
}
|
||||
|
||||
// subst returns a copy of pattern with values from m substituted in place
|
||||
// of wildcards and pos used as the position of tokens from the pattern.
|
||||
// if m == nil, subst returns a copy of pattern and doesn't change the line
|
||||
// number information.
|
||||
func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
|
||||
if !pattern.IsValid() {
|
||||
return reflect.Value{}
|
||||
}
|
||||
|
||||
// Wildcard gets replaced with map value.
|
||||
if m != nil && pattern.Type() == identType {
|
||||
name := pattern.Interface().(*ast.Ident).Name
|
||||
if isWildcard(name) {
|
||||
if old, ok := m[name]; ok {
|
||||
return subst(nil, old, reflect.Value{})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if pos.IsValid() && pattern.Type() == positionType {
|
||||
// use new position only if old position was valid in the first place
|
||||
if old := pattern.Interface().(token.Pos); !old.IsValid() {
|
||||
return pattern
|
||||
}
|
||||
return pos
|
||||
}
|
||||
|
||||
// Otherwise copy.
|
||||
switch p := pattern; p.Kind() {
|
||||
case reflect.Slice:
|
||||
v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
|
||||
for i := 0; i < p.Len(); i++ {
|
||||
v.Index(i).Set(subst(m, p.Index(i), pos))
|
||||
}
|
||||
return v
|
||||
|
||||
case reflect.Struct:
|
||||
v := reflect.New(p.Type()).Elem()
|
||||
for i := 0; i < p.NumField(); i++ {
|
||||
v.Field(i).Set(subst(m, p.Field(i), pos))
|
||||
}
|
||||
return v
|
||||
|
||||
case reflect.Ptr:
|
||||
v := reflect.New(p.Type()).Elem()
|
||||
if elem := p.Elem(); elem.IsValid() {
|
||||
v.Set(subst(m, elem, pos).Addr())
|
||||
}
|
||||
return v
|
||||
|
||||
case reflect.Interface:
|
||||
v := reflect.New(p.Type()).Elem()
|
||||
if elem := p.Elem(); elem.IsValid() {
|
||||
v.Set(subst(m, elem, pos))
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
return pattern
|
||||
}
|
121
libgo/go/cmd/gofmt/simplify.go
Normal file
121
libgo/go/cmd/gofmt/simplify.go
Normal file
@ -0,0 +1,121 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type simplifier struct {
|
||||
hasDotImport bool // package file contains: import . "some/import/path"
|
||||
}
|
||||
|
||||
func (s *simplifier) Visit(node ast.Node) ast.Visitor {
|
||||
switch n := node.(type) {
|
||||
case *ast.CompositeLit:
|
||||
// array, slice, and map composite literals may be simplified
|
||||
outer := n
|
||||
var eltType ast.Expr
|
||||
switch typ := outer.Type.(type) {
|
||||
case *ast.ArrayType:
|
||||
eltType = typ.Elt
|
||||
case *ast.MapType:
|
||||
eltType = typ.Value
|
||||
}
|
||||
|
||||
if eltType != nil {
|
||||
typ := reflect.ValueOf(eltType)
|
||||
for i, x := range outer.Elts {
|
||||
px := &outer.Elts[i]
|
||||
// look at value of indexed/named elements
|
||||
if t, ok := x.(*ast.KeyValueExpr); ok {
|
||||
x = t.Value
|
||||
px = &t.Value
|
||||
}
|
||||
ast.Walk(s, x) // simplify x
|
||||
// if the element is a composite literal and its literal type
|
||||
// matches the outer literal's element type exactly, the inner
|
||||
// literal type may be omitted
|
||||
if inner, ok := x.(*ast.CompositeLit); ok {
|
||||
if match(nil, typ, reflect.ValueOf(inner.Type)) {
|
||||
inner.Type = nil
|
||||
}
|
||||
}
|
||||
// if the outer literal's element type is a pointer type *T
|
||||
// and the element is & of a composite literal of type T,
|
||||
// the inner &T may be omitted.
|
||||
if ptr, ok := eltType.(*ast.StarExpr); ok {
|
||||
if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
|
||||
if inner, ok := addr.X.(*ast.CompositeLit); ok {
|
||||
if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
|
||||
inner.Type = nil // drop T
|
||||
*px = inner // drop &
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// node was simplified - stop walk (there are no subnodes to simplify)
|
||||
return nil
|
||||
}
|
||||
|
||||
case *ast.SliceExpr:
|
||||
// a slice expression of the form: s[a:len(s)]
|
||||
// can be simplified to: s[a:]
|
||||
// if s is "simple enough" (for now we only accept identifiers)
|
||||
if s.hasDotImport {
|
||||
// if dot imports are present, we cannot be certain that an
|
||||
// unresolved "len" identifier refers to the predefined len()
|
||||
break
|
||||
}
|
||||
if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
|
||||
// the array/slice object is a single, resolved identifier
|
||||
if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() {
|
||||
// the high expression is a function call with a single argument
|
||||
if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" && fun.Obj == nil {
|
||||
// the function called is "len" and it is not locally defined; and
|
||||
// because we don't have dot imports, it must be the predefined len()
|
||||
if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Obj == s.Obj {
|
||||
// the len argument is the array/slice object
|
||||
n.High = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Note: We could also simplify slice expressions of the form s[0:b] to s[:b]
|
||||
// but we leave them as is since sometimes we want to be very explicit
|
||||
// about the lower bound.
|
||||
// An example where the 0 helps:
|
||||
// x, y, z := b[0:2], b[2:4], b[4:6]
|
||||
// An example where it does not:
|
||||
// x, y := b[:n], b[n:]
|
||||
|
||||
case *ast.RangeStmt:
|
||||
// a range of the form: for x, _ = range v {...}
|
||||
// can be simplified to: for x = range v {...}
|
||||
if ident, _ := n.Value.(*ast.Ident); ident != nil && ident.Name == "_" {
|
||||
n.Value = nil
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func simplify(f *ast.File) {
|
||||
var s simplifier
|
||||
|
||||
// determine if f contains dot imports
|
||||
for _, imp := range f.Imports {
|
||||
if imp.Name != nil && imp.Name.Name == "." {
|
||||
s.hasDotImport = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
ast.Walk(&s, f)
|
||||
}
|
9
libgo/go/cmd/gofmt/testdata/comments.golden
vendored
Normal file
9
libgo/go/cmd/gofmt/testdata/comments.golden
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
|
||||
// comment here
|
||||
|
||||
func f() {}
|
||||
|
||||
//line foo.go:1
|
9
libgo/go/cmd/gofmt/testdata/comments.input
vendored
Normal file
9
libgo/go/cmd/gofmt/testdata/comments.input
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
|
||||
// comment here
|
||||
|
||||
func f() {}
|
||||
|
||||
//line foo.go:1
|
202
libgo/go/cmd/gofmt/testdata/composites.golden
vendored
Normal file
202
libgo/go/cmd/gofmt/testdata/composites.golden
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
package P
|
||||
|
||||
type T struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
var _ = [42]T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = [...]T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []T{
|
||||
{},
|
||||
10: {1, 2},
|
||||
20: {3, 4},
|
||||
}
|
||||
|
||||
var _ = []struct {
|
||||
x, y int
|
||||
}{
|
||||
{},
|
||||
10: {1, 2},
|
||||
20: {3, 4},
|
||||
}
|
||||
|
||||
var _ = []interface{}{
|
||||
T{},
|
||||
10: T{1, 2},
|
||||
20: T{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][]int{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][]int{
|
||||
([]int{}),
|
||||
([]int{1, 2}),
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][][]int{
|
||||
{},
|
||||
{
|
||||
{},
|
||||
{0, 1, 2, 3},
|
||||
{4, 5},
|
||||
},
|
||||
}
|
||||
|
||||
var _ = map[string]T{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]struct {
|
||||
x, y int
|
||||
}{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]interface{}{
|
||||
"foo": T{},
|
||||
"bar": T{1, 2},
|
||||
"bal": T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string][]int{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string][]int{
|
||||
"foo": ([]int{}),
|
||||
"bar": ([]int{1, 2}),
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
// from exp/4s/data.go
|
||||
var pieces4 = []Piece{
|
||||
{0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
|
||||
{1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
|
||||
{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
|
||||
{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
|
||||
}
|
||||
|
||||
var _ = [42]*T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = [...]*T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*T{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*T{
|
||||
{},
|
||||
10: {1, 2},
|
||||
20: {3, 4},
|
||||
}
|
||||
|
||||
var _ = []*struct {
|
||||
x, y int
|
||||
}{
|
||||
{},
|
||||
10: {1, 2},
|
||||
20: {3, 4},
|
||||
}
|
||||
|
||||
var _ = []interface{}{
|
||||
&T{},
|
||||
10: &T{1, 2},
|
||||
20: &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]int{
|
||||
{},
|
||||
{1, 2},
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]int{
|
||||
(&[]int{}),
|
||||
(&[]int{1, 2}),
|
||||
{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]*[]int{
|
||||
{},
|
||||
{
|
||||
{},
|
||||
{0, 1, 2, 3},
|
||||
{4, 5},
|
||||
},
|
||||
}
|
||||
|
||||
var _ = map[string]*T{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*struct {
|
||||
x, y int
|
||||
}{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]interface{}{
|
||||
"foo": &T{},
|
||||
"bar": &T{1, 2},
|
||||
"bal": &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*[]int{
|
||||
"foo": {},
|
||||
"bar": {1, 2},
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*[]int{
|
||||
"foo": (&[]int{}),
|
||||
"bar": (&[]int{1, 2}),
|
||||
"bal": {3, 4},
|
||||
}
|
||||
|
||||
var pieces4 = []*Piece{
|
||||
{0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
|
||||
{1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
|
||||
{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
|
||||
{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
|
||||
}
|
202
libgo/go/cmd/gofmt/testdata/composites.input
vendored
Normal file
202
libgo/go/cmd/gofmt/testdata/composites.input
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
package P
|
||||
|
||||
type T struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
var _ = [42]T{
|
||||
T{},
|
||||
T{1, 2},
|
||||
T{3, 4},
|
||||
}
|
||||
|
||||
var _ = [...]T{
|
||||
T{},
|
||||
T{1, 2},
|
||||
T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []T{
|
||||
T{},
|
||||
T{1, 2},
|
||||
T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []T{
|
||||
T{},
|
||||
10: T{1, 2},
|
||||
20: T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []struct {
|
||||
x, y int
|
||||
}{
|
||||
struct{ x, y int }{},
|
||||
10: struct{ x, y int }{1, 2},
|
||||
20: struct{ x, y int }{3, 4},
|
||||
}
|
||||
|
||||
var _ = []interface{}{
|
||||
T{},
|
||||
10: T{1, 2},
|
||||
20: T{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][]int{
|
||||
[]int{},
|
||||
[]int{1, 2},
|
||||
[]int{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][]int{
|
||||
([]int{}),
|
||||
([]int{1, 2}),
|
||||
[]int{3, 4},
|
||||
}
|
||||
|
||||
var _ = [][][]int{
|
||||
[][]int{},
|
||||
[][]int{
|
||||
[]int{},
|
||||
[]int{0, 1, 2, 3},
|
||||
[]int{4, 5},
|
||||
},
|
||||
}
|
||||
|
||||
var _ = map[string]T{
|
||||
"foo": T{},
|
||||
"bar": T{1, 2},
|
||||
"bal": T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]struct {
|
||||
x, y int
|
||||
}{
|
||||
"foo": struct{ x, y int }{},
|
||||
"bar": struct{ x, y int }{1, 2},
|
||||
"bal": struct{ x, y int }{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]interface{}{
|
||||
"foo": T{},
|
||||
"bar": T{1, 2},
|
||||
"bal": T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string][]int{
|
||||
"foo": []int{},
|
||||
"bar": []int{1, 2},
|
||||
"bal": []int{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string][]int{
|
||||
"foo": ([]int{}),
|
||||
"bar": ([]int{1, 2}),
|
||||
"bal": []int{3, 4},
|
||||
}
|
||||
|
||||
// from exp/4s/data.go
|
||||
var pieces4 = []Piece{
|
||||
Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
|
||||
Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
|
||||
Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
|
||||
Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
|
||||
}
|
||||
|
||||
var _ = [42]*T{
|
||||
&T{},
|
||||
&T{1, 2},
|
||||
&T{3, 4},
|
||||
}
|
||||
|
||||
var _ = [...]*T{
|
||||
&T{},
|
||||
&T{1, 2},
|
||||
&T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*T{
|
||||
&T{},
|
||||
&T{1, 2},
|
||||
&T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*T{
|
||||
&T{},
|
||||
10: &T{1, 2},
|
||||
20: &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*struct {
|
||||
x, y int
|
||||
}{
|
||||
&struct{ x, y int }{},
|
||||
10: &struct{ x, y int }{1, 2},
|
||||
20: &struct{ x, y int }{3, 4},
|
||||
}
|
||||
|
||||
var _ = []interface{}{
|
||||
&T{},
|
||||
10: &T{1, 2},
|
||||
20: &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]int{
|
||||
&[]int{},
|
||||
&[]int{1, 2},
|
||||
&[]int{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]int{
|
||||
(&[]int{}),
|
||||
(&[]int{1, 2}),
|
||||
&[]int{3, 4},
|
||||
}
|
||||
|
||||
var _ = []*[]*[]int{
|
||||
&[]*[]int{},
|
||||
&[]*[]int{
|
||||
&[]int{},
|
||||
&[]int{0, 1, 2, 3},
|
||||
&[]int{4, 5},
|
||||
},
|
||||
}
|
||||
|
||||
var _ = map[string]*T{
|
||||
"foo": &T{},
|
||||
"bar": &T{1, 2},
|
||||
"bal": &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*struct {
|
||||
x, y int
|
||||
}{
|
||||
"foo": &struct{ x, y int }{},
|
||||
"bar": &struct{ x, y int }{1, 2},
|
||||
"bal": &struct{ x, y int }{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]interface{}{
|
||||
"foo": &T{},
|
||||
"bar": &T{1, 2},
|
||||
"bal": &T{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*[]int{
|
||||
"foo": &[]int{},
|
||||
"bar": &[]int{1, 2},
|
||||
"bal": &[]int{3, 4},
|
||||
}
|
||||
|
||||
var _ = map[string]*[]int{
|
||||
"foo": (&[]int{}),
|
||||
"bar": (&[]int{1, 2}),
|
||||
"bal": &[]int{3, 4},
|
||||
}
|
||||
|
||||
var pieces4 = []*Piece{
|
||||
&Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
|
||||
&Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
|
||||
&Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
|
||||
&Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
|
||||
}
|
12
libgo/go/cmd/gofmt/testdata/crlf.golden
vendored
Normal file
12
libgo/go/cmd/gofmt/testdata/crlf.golden
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
Source containing CR/LF line endings.
|
||||
The gofmt'ed output must only have LF
|
||||
line endings.
|
||||
*/
|
||||
package main
|
||||
|
||||
func main() {
|
||||
// line comment
|
||||
println("hello, world!") // another line comment
|
||||
println()
|
||||
}
|
12
libgo/go/cmd/gofmt/testdata/crlf.input
vendored
Normal file
12
libgo/go/cmd/gofmt/testdata/crlf.input
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
Source containing CR/LF line endings.
|
||||
The gofmt'ed output must only have LF
|
||||
line endings.
|
||||
*/
|
||||
package main
|
||||
|
||||
func main() {
|
||||
// line comment
|
||||
println("hello, world!") // another line comment
|
||||
println()
|
||||
}
|
126
libgo/go/cmd/gofmt/testdata/import.golden
vendored
Normal file
126
libgo/go/cmd/gofmt/testdata/import.golden
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
// a block with comments
|
||||
"errors"
|
||||
"fmt" // for Printf
|
||||
"io" // for Reader
|
||||
"log" // for Fatal
|
||||
"math"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt" // for Printf
|
||||
|
||||
"math"
|
||||
|
||||
"log" // for Fatal
|
||||
|
||||
"errors"
|
||||
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
import (
|
||||
// for Printf
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
// for Fatal
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
// for Reader
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt" // for Printf
|
||||
"io" // for Reader
|
||||
"log" // for Fatal
|
||||
"math"
|
||||
|
||||
"fmt" // for Printf
|
||||
|
||||
"math"
|
||||
|
||||
"log" // for Fatal
|
||||
|
||||
"errors"
|
||||
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt" // for Printf
|
||||
|
||||
"errors"
|
||||
"io" // for Reader
|
||||
"log" // for Fatal
|
||||
"math"
|
||||
|
||||
"errors"
|
||||
"fmt" // for Printf
|
||||
"io" // for Reader
|
||||
"log" // for Fatal
|
||||
"math"
|
||||
)
|
||||
|
||||
// Test deduping and extended sorting
|
||||
import (
|
||||
a "A" // aA
|
||||
b "A" // bA1
|
||||
b "A" // bA2
|
||||
"B" // B
|
||||
. "B" // .B
|
||||
_ "B" // _b
|
||||
"C"
|
||||
a "D" // aD
|
||||
)
|
||||
|
||||
import (
|
||||
"dedup_by_group"
|
||||
|
||||
"dedup_by_group"
|
||||
)
|
131
libgo/go/cmd/gofmt/testdata/import.input
vendored
Normal file
131
libgo/go/cmd/gofmt/testdata/import.input
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"log"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"log"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
// a block with comments
|
||||
"fmt" // for Printf
|
||||
"math"
|
||||
"log" // for Fatal
|
||||
"errors"
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt" // for Printf
|
||||
|
||||
"math"
|
||||
|
||||
"log" // for Fatal
|
||||
|
||||
"errors"
|
||||
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
import (
|
||||
// for Printf
|
||||
"fmt"
|
||||
|
||||
"math"
|
||||
|
||||
// for Fatal
|
||||
"log"
|
||||
|
||||
"errors"
|
||||
|
||||
// for Reader
|
||||
"io"
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt" // for Printf
|
||||
"math"
|
||||
"log" // for Fatal
|
||||
"errors"
|
||||
"io" // for Reader
|
||||
|
||||
"fmt" // for Printf
|
||||
|
||||
"math"
|
||||
|
||||
"log" // for Fatal
|
||||
|
||||
"errors"
|
||||
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
import (
|
||||
"fmt" // for Printf
|
||||
|
||||
"math"
|
||||
"log" // for Fatal
|
||||
"errors"
|
||||
"io" // for Reader
|
||||
|
||||
"fmt" // for Printf
|
||||
"math"
|
||||
"log" // for Fatal
|
||||
"errors"
|
||||
"io" // for Reader
|
||||
)
|
||||
|
||||
// Test deduping and extended sorting
|
||||
import (
|
||||
"B" // B
|
||||
a "A" // aA
|
||||
b "A" // bA2
|
||||
b "A" // bA1
|
||||
. "B" // .B
|
||||
. "B"
|
||||
"C"
|
||||
"C"
|
||||
"C"
|
||||
a "D" // aD
|
||||
"B"
|
||||
_ "B" // _b
|
||||
)
|
||||
|
||||
import (
|
||||
"dedup_by_group"
|
||||
"dedup_by_group"
|
||||
|
||||
"dedup_by_group"
|
||||
)
|
9
libgo/go/cmd/gofmt/testdata/old.golden
vendored
Normal file
9
libgo/go/cmd/gofmt/testdata/old.golden
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package P
|
||||
|
||||
func f() {
|
||||
if x {
|
||||
y
|
||||
} else {
|
||||
z
|
||||
}
|
||||
}
|
8
libgo/go/cmd/gofmt/testdata/old.input
vendored
Normal file
8
libgo/go/cmd/gofmt/testdata/old.input
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
package P
|
||||
|
||||
func f() {
|
||||
if x {
|
||||
y
|
||||
} else
|
||||
z
|
||||
}
|
12
libgo/go/cmd/gofmt/testdata/rewrite1.golden
vendored
Normal file
12
libgo/go/cmd/gofmt/testdata/rewrite1.golden
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
type Bar int
|
||||
|
||||
func main() {
|
||||
var a Bar
|
||||
println(a)
|
||||
}
|
12
libgo/go/cmd/gofmt/testdata/rewrite1.input
vendored
Normal file
12
libgo/go/cmd/gofmt/testdata/rewrite1.input
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
type Foo int
|
||||
|
||||
func main() {
|
||||
var a Foo
|
||||
println(a)
|
||||
}
|
10
libgo/go/cmd/gofmt/testdata/rewrite2.golden
vendored
Normal file
10
libgo/go/cmd/gofmt/testdata/rewrite2.golden
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
// 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.
|
||||
|
||||
package p
|
||||
|
||||
// Slices have nil Len values in the corresponding ast.ArrayType
|
||||
// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
|
||||
// The rewriter must not crash in that case. Was issue 1696.
|
||||
func f() []bool {}
|
10
libgo/go/cmd/gofmt/testdata/rewrite2.input
vendored
Normal file
10
libgo/go/cmd/gofmt/testdata/rewrite2.input
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
// 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.
|
||||
|
||||
package p
|
||||
|
||||
// Slices have nil Len values in the corresponding ast.ArrayType
|
||||
// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
|
||||
// The rewriter must not crash in that case. Was issue 1696.
|
||||
func f() []int {}
|
12
libgo/go/cmd/gofmt/testdata/rewrite3.golden
vendored
Normal file
12
libgo/go/cmd/gofmt/testdata/rewrite3.golden
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
// Field tags are *ast.BasicLit nodes that are nil when the tag is
|
||||
// absent. These nil nodes must not be mistaken for expressions,
|
||||
// the rewriter should not try to dereference them. Was issue 2410.
|
||||
type Foo struct {
|
||||
Field int
|
||||
}
|
12
libgo/go/cmd/gofmt/testdata/rewrite3.input
vendored
Normal file
12
libgo/go/cmd/gofmt/testdata/rewrite3.input
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
// Field tags are *ast.BasicLit nodes that are nil when the tag is
|
||||
// absent. These nil nodes must not be mistaken for expressions,
|
||||
// the rewriter should not try to dereference them. Was issue 2410.
|
||||
type Foo struct {
|
||||
Field int
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user