mirror of
https://github.com/golang/go
synced 2024-11-22 04:34:39 -07:00
go/build: replace FindTree, ScanDir, Tree, DirInfo with Import, Package
This is an API change, but one I have been promising would happen when it was clear what the go command needed. This is basically a complete replacement of what used to be here. build.Tree is gone. build.DirInfo is expanded and now called build.Package. build.FindTree is now build.Import(package, srcDir, build.FindOnly). The returned *Package contains information that FindTree returned, but applicable only to a single package. build.ScanDir is now build.ImportDir. build.FindTree+build.ScanDir is now build.Import. The new Import API allows specifying the source directory, in order to resolve local imports (import "./foo") and also allows scanning of packages outside of $GOPATH. They will come back with less information in the Package, but they will still work. The old go/build API exposed both too much and too little. This API is much closer to what the go command needs, and it works well enough in the other places where it is used. Path is gone, so it can no longer be misused. (Fixes issue 2749.) This CL updates clients of go/build other than the go command. The go command changes are in a separate CL, to be submitted at the same time. R=golang-dev, r, alex.brainman, adg CC=golang-dev https://golang.org/cl/5713043
This commit is contained in:
parent
a72b87efa9
commit
ebe1664d27
@ -74,16 +74,10 @@ func main() {
|
||||
pkgs = strings.Fields(string(stds))
|
||||
}
|
||||
|
||||
tree, _, err := build.FindTree("os") // some known package
|
||||
if err != nil {
|
||||
log.Fatalf("failed to find tree: %v", err)
|
||||
}
|
||||
|
||||
var featureCtx = make(map[string]map[string]bool) // feature -> context name -> true
|
||||
for _, context := range contexts {
|
||||
w := NewWalker()
|
||||
w.context = context
|
||||
w.tree = tree
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
w.wantedPkg[pkg] = true
|
||||
@ -95,7 +89,7 @@ func main() {
|
||||
strings.HasPrefix(pkg, "old/") {
|
||||
continue
|
||||
}
|
||||
if !tree.HasSrc(pkg) {
|
||||
if fi, err := os.Stat(filepath.Join(w.root, pkg)); err != nil || !fi.IsDir() {
|
||||
log.Fatalf("no source in tree for package %q", pkg)
|
||||
}
|
||||
w.WalkPackage(pkg)
|
||||
@ -165,7 +159,7 @@ type pkgSymbol struct {
|
||||
|
||||
type Walker struct {
|
||||
context *build.Context
|
||||
tree *build.Tree
|
||||
root string
|
||||
fset *token.FileSet
|
||||
scope []string
|
||||
features map[string]bool // set
|
||||
@ -191,6 +185,7 @@ func NewWalker() *Walker {
|
||||
selectorFullPkg: make(map[string]string),
|
||||
wantedPkg: make(map[string]bool),
|
||||
prevConstType: make(map[pkgSymbol]string),
|
||||
root: filepath.Join(build.Default.GOROOT, "src/pkg"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,15 +247,13 @@ func (w *Walker) WalkPackage(name string) {
|
||||
defer func() {
|
||||
w.packageState[name] = loaded
|
||||
}()
|
||||
dir := filepath.Join(w.tree.SrcDir(), filepath.FromSlash(name))
|
||||
dir := filepath.Join(w.root, filepath.FromSlash(name))
|
||||
|
||||
var info *build.DirInfo
|
||||
var err error
|
||||
if ctx := w.context; ctx != nil {
|
||||
info, err = ctx.ScanDir(dir)
|
||||
} else {
|
||||
info, err = build.ScanDir(dir)
|
||||
ctxt := w.context
|
||||
if ctxt == nil {
|
||||
ctxt = &build.Default
|
||||
}
|
||||
info, err := ctxt.ImportDir(dir, 0)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no Go source files") {
|
||||
return
|
||||
|
@ -7,7 +7,6 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -36,7 +35,7 @@ func TestGolden(t *testing.T) {
|
||||
w := NewWalker()
|
||||
w.wantedPkg[fi.Name()] = true
|
||||
|
||||
w.tree = &build.Tree{Path: "testdata", Goroot: true}
|
||||
w.root = "testdata/src/pkg"
|
||||
goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt")
|
||||
w.WalkPackage(fi.Name())
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"go/printer"
|
||||
"go/token"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@ -90,11 +91,11 @@ var (
|
||||
|
||||
func initHandlers() {
|
||||
paths := filepath.SplitList(*pkgPath)
|
||||
for _, t := range build.Path {
|
||||
if t.Goroot {
|
||||
continue
|
||||
gorootSrc := filepath.Join(build.Default.GOROOT, "src", "pkg")
|
||||
for _, p := range build.Default.SrcDirs() {
|
||||
if p != gorootSrc {
|
||||
paths = append(paths, p)
|
||||
}
|
||||
paths = append(paths, t.SrcDir())
|
||||
}
|
||||
fsMap.Init(paths)
|
||||
|
||||
@ -1002,11 +1003,13 @@ func fsReadDir(dir string) ([]os.FileInfo, error) {
|
||||
return fs.ReadDir(dir)
|
||||
}
|
||||
|
||||
// fsReadFile implements ReadFile for the go/build package.
|
||||
func fsReadFile(dir, name string) (path string, data []byte, err error) {
|
||||
path = filepath.Join(dir, name)
|
||||
data, err = ReadFile(fs, path)
|
||||
return
|
||||
// fsOpenFile implements OpenFile for the go/build package.
|
||||
func fsOpenFile(name string) (r io.ReadCloser, err error) {
|
||||
data, err := ReadFile(fs, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ioutil.NopCloser(bytes.NewReader(data)), nil
|
||||
}
|
||||
|
||||
func inList(name string, list []string) bool {
|
||||
@ -1039,10 +1042,11 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
|
||||
// To use different pair, such as if we allowed the user
|
||||
// to choose, set ctxt.GOOS and ctxt.GOARCH before
|
||||
// calling ctxt.ScanDir.
|
||||
ctxt := build.DefaultContext
|
||||
ctxt := build.Default
|
||||
ctxt.IsAbsPath = path.IsAbs
|
||||
ctxt.ReadDir = fsReadDir
|
||||
ctxt.ReadFile = fsReadFile
|
||||
dir, err := ctxt.ScanDir(abspath)
|
||||
ctxt.OpenFile = fsOpenFile
|
||||
dir, err := ctxt.ImportDir(abspath, 0)
|
||||
if err == nil {
|
||||
pkgFiles = append(dir.GoFiles, dir.CgoFiles...)
|
||||
}
|
||||
|
@ -388,9 +388,9 @@ func main() {
|
||||
}
|
||||
relpath := path
|
||||
abspath := path
|
||||
if t, pkg, err := build.FindTree(path); err == nil {
|
||||
relpath = pkg
|
||||
abspath = filepath.Join(t.SrcDir(), pkg)
|
||||
if bp, _ := build.Import(path, "", build.FindOnly); bp.Dir != "" && bp.ImportPath != "" {
|
||||
relpath = bp.ImportPath
|
||||
abspath = bp.Dir
|
||||
} else if !filepath.IsAbs(path) {
|
||||
abspath = absolutePath(path, pkgHandler.fsRoot)
|
||||
} else {
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/scanner"
|
||||
)
|
||||
|
||||
@ -39,11 +40,14 @@ func findPkg(path string) (filename, id string) {
|
||||
switch path[0] {
|
||||
default:
|
||||
// "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
|
||||
tree, pkg, err := build.FindTree(path)
|
||||
if err != nil {
|
||||
bp, _ := build.Import(path, "", build.FindOnly)
|
||||
if bp.PkgObj == "" {
|
||||
return
|
||||
}
|
||||
noext = filepath.Join(tree.PkgDir(), pkg)
|
||||
noext = bp.PkgObj
|
||||
if strings.HasSuffix(noext, ".a") {
|
||||
noext = noext[:len(noext)-2]
|
||||
}
|
||||
|
||||
case '.':
|
||||
// "./x" -> "/this/directory/x.ext", "/this/directory/x"
|
||||
@ -742,7 +746,7 @@ func (p *gcParser) parseVarDecl() {
|
||||
}
|
||||
|
||||
// FuncBody = "{" ... "}" .
|
||||
//
|
||||
//
|
||||
func (p *gcParser) parseFuncBody() {
|
||||
p.expect('{')
|
||||
for i := 1; i > 0; p.next() {
|
||||
|
@ -48,7 +48,7 @@
|
||||
// To build a file only when using cgo, and only on Linux and OS X:
|
||||
//
|
||||
// // +build linux,cgo darwin,cgo
|
||||
//
|
||||
//
|
||||
// Such a file is usually paired with another file implementing the
|
||||
// default functionality for other systems, which in this case would
|
||||
// carry the constraint:
|
||||
@ -66,12 +66,14 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/doc"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
@ -84,56 +86,186 @@ import (
|
||||
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
|
||||
BuildTags []string // additional tags to recognize in +build lines
|
||||
UseAllFiles bool // use files regardless of +build lines, file names
|
||||
Gccgo bool // assume use of gccgo when computing object paths
|
||||
|
||||
// By default, ScanDir uses the operating system's
|
||||
// file system calls to read directories and files.
|
||||
// Callers can override those calls to provide other
|
||||
// ways to read data by setting ReadDir and ReadFile.
|
||||
// ScanDir does not make any assumptions about the
|
||||
// format of the strings dir and file: they can be
|
||||
// slash-separated, backslash-separated, even URLs.
|
||||
// By default, Import uses the operating system's file system calls
|
||||
// to read directories and files. To read from other sources,
|
||||
// callers can set the following functions. They all have default
|
||||
// behaviors that use the local file system, so clients need only set
|
||||
// the functions whose behaviors they wish to change.
|
||||
|
||||
// JoinPath joins the sequence of path fragments into a single path.
|
||||
// If JoinPath is nil, Import uses filepath.Join.
|
||||
JoinPath func(elem ...string) string
|
||||
|
||||
// SplitPathList splits the path list into a slice of individual paths.
|
||||
// If SplitPathList is nil, Import uses filepath.SplitList.
|
||||
SplitPathList func(list string) []string
|
||||
|
||||
// IsAbsPath reports whether path is an absolute path.
|
||||
// If IsAbsPath is nil, Import uses filepath.IsAbs.
|
||||
IsAbsPath func(path string) bool
|
||||
|
||||
// IsDir reports whether the path names a directory.
|
||||
// If IsDir is nil, Import calls os.Stat and uses the result's IsDir method.
|
||||
IsDir func(path string) bool
|
||||
|
||||
// HasSubdir reports whether dir is a subdirectory of
|
||||
// (perhaps multiple levels below) root.
|
||||
// If so, HasSubdir sets rel to a slash-separated path that
|
||||
// can be joined to root to produce a path equivalent to dir.
|
||||
// If HasSubdir is nil, Import uses an implementation built on
|
||||
// filepath.EvalSymlinks.
|
||||
HasSubdir func(root, dir string) (rel string, ok bool)
|
||||
|
||||
// ReadDir returns a slice of os.FileInfo, sorted by Name,
|
||||
// describing the content of the named directory.
|
||||
// The dir argument is the argument to ScanDir.
|
||||
// If ReadDir is nil, ScanDir uses io.ReadDir.
|
||||
// If ReadDir is nil, Import uses io.ReadDir.
|
||||
ReadDir func(dir string) (fi []os.FileInfo, err error)
|
||||
|
||||
// ReadFile returns the content of the file named file
|
||||
// in the directory named dir. The dir argument is the
|
||||
// argument to ScanDir, and the file argument is the
|
||||
// Name field from an os.FileInfo returned by ReadDir.
|
||||
// The returned path is the full name of the file, to be
|
||||
// used in error messages.
|
||||
//
|
||||
// If ReadFile is nil, ScanDir uses filepath.Join(dir, file)
|
||||
// as the path and ioutil.ReadFile to read the data.
|
||||
ReadFile func(dir, file string) (path string, content []byte, err error)
|
||||
// OpenFile opens a file (not a directory) for reading.
|
||||
// If OpenFile is nil, Import uses os.Open.
|
||||
OpenFile func(path string) (r io.ReadCloser, err error)
|
||||
}
|
||||
|
||||
func (ctxt *Context) readDir(dir string) ([]os.FileInfo, error) {
|
||||
// joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join.
|
||||
func (ctxt *Context) joinPath(elem ...string) string {
|
||||
if f := ctxt.JoinPath; f != nil {
|
||||
return f(elem...)
|
||||
}
|
||||
return filepath.Join(elem...)
|
||||
}
|
||||
|
||||
// splitPathList calls ctxt.SplitPathList (if not nil) or else filepath.SplitList.
|
||||
func (ctxt *Context) splitPathList(s string) []string {
|
||||
if f := ctxt.SplitPathList; f != nil {
|
||||
return f(s)
|
||||
}
|
||||
return filepath.SplitList(s)
|
||||
}
|
||||
|
||||
// isAbsPath calls ctxt.IsAbsSPath (if not nil) or else filepath.IsAbs.
|
||||
func (ctxt *Context) isAbsPath(path string) bool {
|
||||
if f := ctxt.IsAbsPath; f != nil {
|
||||
return f(path)
|
||||
}
|
||||
return filepath.IsAbs(path)
|
||||
}
|
||||
|
||||
// isDir calls ctxt.IsDir (if not nil) or else uses os.Stat.
|
||||
func (ctxt *Context) isDir(path string) bool {
|
||||
if f := ctxt.IsDir; f != nil {
|
||||
return f(path)
|
||||
}
|
||||
fi, err := os.Stat(path)
|
||||
return err == nil && fi.IsDir()
|
||||
}
|
||||
|
||||
// hasSubdir calls ctxt.HasSubdir (if not nil) or else uses
|
||||
// the local file system to answer the question.
|
||||
func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) {
|
||||
if f := ctxt.HasSubdir; f != nil {
|
||||
return f(root, dir)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir.
|
||||
func (ctxt *Context) readDir(path string) ([]os.FileInfo, error) {
|
||||
if f := ctxt.ReadDir; f != nil {
|
||||
return f(dir)
|
||||
return f(path)
|
||||
}
|
||||
return ioutil.ReadDir(dir)
|
||||
return ioutil.ReadDir(path)
|
||||
}
|
||||
|
||||
func (ctxt *Context) readFile(dir, file string) (string, []byte, error) {
|
||||
if f := ctxt.ReadFile; f != nil {
|
||||
return f(dir, file)
|
||||
// openFile calls ctxt.OpenFile (if not nil) or else os.Open.
|
||||
func (ctxt *Context) openFile(path string) (io.ReadCloser, error) {
|
||||
if fn := ctxt.OpenFile; fn != nil {
|
||||
return fn(path)
|
||||
}
|
||||
p := filepath.Join(dir, file)
|
||||
content, err := ioutil.ReadFile(p)
|
||||
return p, content, err
|
||||
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err // nil interface
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// The DefaultContext is the default Context for builds.
|
||||
// It uses the GOARCH and GOOS environment variables
|
||||
// if set, or else the compiled code's GOARCH and GOOS.
|
||||
var DefaultContext Context = defaultContext()
|
||||
// isFile determines whether path is a file by trying to open it.
|
||||
// It reuses openFile instead of adding another function to the
|
||||
// list in Context.
|
||||
func (ctxt *Context) isFile(path string) bool {
|
||||
f, err := ctxt.openFile(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
f.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
// gopath returns the list of Go path directories.
|
||||
func (ctxt *Context) gopath() []string {
|
||||
var all []string
|
||||
for _, p := range ctxt.splitPathList(ctxt.GOPATH) {
|
||||
if p == "" || p == ctxt.GOROOT {
|
||||
// Empty paths are uninteresting.
|
||||
// If the path is the GOROOT, ignore it.
|
||||
// People sometimes set GOPATH=$GOROOT, which is useless
|
||||
// but would cause us to find packages with import paths
|
||||
// like "pkg/math".
|
||||
// Do not get confused by this common mistake.
|
||||
continue
|
||||
}
|
||||
all = append(all, p)
|
||||
}
|
||||
return all
|
||||
}
|
||||
|
||||
// SrcDirs returns a list of package source root directories.
|
||||
// It draws from the current Go root and Go path but omits directories
|
||||
// that do not exist.
|
||||
func (ctxt *Context) SrcDirs() []string {
|
||||
var all []string
|
||||
if ctxt.GOROOT != "" {
|
||||
dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
|
||||
if ctxt.isDir(dir) {
|
||||
all = append(all, dir)
|
||||
}
|
||||
}
|
||||
for _, p := range ctxt.gopath() {
|
||||
dir := ctxt.joinPath(p, "src")
|
||||
if ctxt.isDir(dir) {
|
||||
all = append(all, dir)
|
||||
}
|
||||
}
|
||||
return all
|
||||
}
|
||||
|
||||
// Default is the default Context for builds.
|
||||
// It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables
|
||||
// if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
|
||||
var Default Context = defaultContext()
|
||||
|
||||
var cgoEnabled = map[string]bool{
|
||||
"darwin/386": true,
|
||||
@ -151,9 +283,10 @@ func defaultContext() Context {
|
||||
|
||||
c.GOARCH = envOr("GOARCH", runtime.GOARCH)
|
||||
c.GOOS = envOr("GOOS", runtime.GOOS)
|
||||
c.GOROOT = runtime.GOROOT()
|
||||
c.GOPATH = envOr("GOPATH", "")
|
||||
|
||||
s := os.Getenv("CGO_ENABLED")
|
||||
switch s {
|
||||
switch os.Getenv("CGO_ENABLED") {
|
||||
case "1":
|
||||
c.CgoEnabled = true
|
||||
case "0":
|
||||
@ -173,66 +306,203 @@ func envOr(name, def string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
type DirInfo struct {
|
||||
Package string // Name of package in dir
|
||||
PackageComment *ast.CommentGroup // Package comments from GoFiles
|
||||
ImportPath string // Import path of package in dir
|
||||
Imports []string // All packages imported by GoFiles
|
||||
ImportPos map[string][]token.Position // Source code location of imports
|
||||
// An ImportMode controls the behavior of the Import method.
|
||||
type ImportMode uint
|
||||
|
||||
const (
|
||||
// If FindOnly is set, Import stops after locating the directory
|
||||
// that should contain the sources for a package. It does not
|
||||
// read any files in the directory.
|
||||
FindOnly ImportMode = 1 << iota
|
||||
|
||||
// If AllowBinary is set, Import can be satisfied by a compiled
|
||||
// package object without corresponding sources.
|
||||
AllowBinary
|
||||
)
|
||||
|
||||
// A Package describes the Go package found in a directory.
|
||||
type Package struct {
|
||||
Dir string // directory containing package sources
|
||||
Name string // package name
|
||||
Doc string // documentation synopsis
|
||||
ImportPath string // import path of package ("" if unknown)
|
||||
Root string // root of Go tree where this package lives
|
||||
SrcRoot string // package source root directory ("" if unknown)
|
||||
PkgRoot string // package install root directory ("" if unknown)
|
||||
BinDir string // command install directory ("" if unknown)
|
||||
Goroot bool // package found in Go root
|
||||
PkgObj string // installed .a file
|
||||
|
||||
// Source files
|
||||
GoFiles []string // .go files in dir (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
HFiles []string // .h files in dir
|
||||
CFiles []string // .c files in dir
|
||||
SFiles []string // .s (and, when using cgo, .S files in dir)
|
||||
CgoFiles []string // .go files that import "C"
|
||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string // .go source files that import "C"
|
||||
CFiles []string // .c source files
|
||||
HFiles []string // .h source files
|
||||
SFiles []string // .s source files
|
||||
|
||||
// Cgo directives
|
||||
CgoPkgConfig []string // Cgo pkg-config directives
|
||||
CgoCFLAGS []string // Cgo CFLAGS directives
|
||||
CgoLDFLAGS []string // Cgo LDFLAGS directives
|
||||
|
||||
// Dependency information
|
||||
Imports []string // imports from GoFiles, CgoFiles
|
||||
ImportPos map[string][]token.Position // line information for Imports
|
||||
|
||||
// Test information
|
||||
TestGoFiles []string // _test.go files in package
|
||||
XTestGoFiles []string // _test.go files outside package
|
||||
TestImports []string // All packages imported by (X)TestGoFiles
|
||||
TestImportPos map[string][]token.Position
|
||||
TestGoFiles []string // _test.go files in package
|
||||
TestImports []string // imports from TestGoFiles
|
||||
TestImportPos map[string][]token.Position // line information for TestImports
|
||||
XTestGoFiles []string // _test.go files outside package
|
||||
XTestImports []string // imports from XTestGoFiles
|
||||
XTestImportPos map[string][]token.Position // line information for XTestImports
|
||||
}
|
||||
|
||||
func (d *DirInfo) IsCommand() bool {
|
||||
// TODO(rsc): This is at least a little bogus.
|
||||
return d.Package == "main"
|
||||
// IsCommand reports whether the package is considered a
|
||||
// command to be installed (not just a library).
|
||||
// Packages named "main" are treated as commands.
|
||||
func (p *Package) IsCommand() bool {
|
||||
return p.Name == "main"
|
||||
}
|
||||
|
||||
// ScanDir calls DefaultContext.ScanDir.
|
||||
func ScanDir(dir string) (info *DirInfo, err error) {
|
||||
return DefaultContext.ScanDir(dir)
|
||||
// ImportDir is like Import but processes the Go package found in
|
||||
// the named directory.
|
||||
func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
|
||||
return ctxt.Import(".", dir, mode)
|
||||
}
|
||||
|
||||
// TODO(rsc): Move this comment to a more appropriate place.
|
||||
|
||||
// ScanDir returns a structure with details about the Go package
|
||||
// found in the given directory.
|
||||
// Import returns details about the Go package named by the import path,
|
||||
// interpreting local import paths relative to the src directory. If the path
|
||||
// is a local import path naming a package that can be imported using a
|
||||
// standard import path, the returned package will set p.ImportPath to
|
||||
// that path.
|
||||
//
|
||||
// Most .go, .c, .h, and .s files in the directory are considered part
|
||||
// of the package. The exceptions are:
|
||||
// In the directory containing the package, .go, .c, .h, and .s files are
|
||||
// considered part of the package except for:
|
||||
//
|
||||
// - .go files in package main (unless no other package is found)
|
||||
// - .go files in package documentation
|
||||
// - files starting with _ or .
|
||||
// - files with build constraints not satisfied by the context
|
||||
//
|
||||
func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
||||
dirs, err := ctxt.readDir(dir)
|
||||
// If an error occurs, Import returns a non-nil error also returns a non-nil
|
||||
// *Package containing partial information.
|
||||
//
|
||||
func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package, error) {
|
||||
p := &Package{
|
||||
ImportPath: path,
|
||||
}
|
||||
|
||||
var pkga string
|
||||
if ctxt.Gccgo {
|
||||
dir, elem := pathpkg.Split(p.ImportPath)
|
||||
pkga = "pkg/gccgo/" + dir + "lib" + elem + ".a"
|
||||
} else {
|
||||
pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + "/" + p.ImportPath + ".a"
|
||||
}
|
||||
|
||||
binaryOnly := false
|
||||
if IsLocalImport(path) {
|
||||
if src == "" {
|
||||
return p, fmt.Errorf("import %q: import relative to unknown directory", path)
|
||||
}
|
||||
if !ctxt.isAbsPath(path) {
|
||||
p.Dir = ctxt.joinPath(src, path)
|
||||
}
|
||||
// Determine canonical import path, if any.
|
||||
if ctxt.GOROOT != "" {
|
||||
root := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
|
||||
if sub, ok := ctxt.hasSubdir(root, p.Dir); ok {
|
||||
p.Goroot = true
|
||||
p.ImportPath = sub
|
||||
p.Root = ctxt.GOROOT
|
||||
goto Found
|
||||
}
|
||||
}
|
||||
all := ctxt.gopath()
|
||||
for i, root := range all {
|
||||
rootsrc := ctxt.joinPath(root, "src")
|
||||
if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok {
|
||||
// We found a potential import path for dir,
|
||||
// but check that using it wouldn't find something
|
||||
// else first.
|
||||
if ctxt.GOROOT != "" {
|
||||
if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
|
||||
goto Found
|
||||
}
|
||||
}
|
||||
for _, earlyRoot := range all[:i] {
|
||||
if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) {
|
||||
goto Found
|
||||
}
|
||||
}
|
||||
|
||||
// sub would not name some other directory instead of this one.
|
||||
// Record it.
|
||||
p.ImportPath = sub
|
||||
p.Root = root
|
||||
goto Found
|
||||
}
|
||||
}
|
||||
// It's okay that we didn't find a root containing dir.
|
||||
// Keep going with the information we have.
|
||||
} else {
|
||||
if strings.HasPrefix(path, "/") {
|
||||
return p, fmt.Errorf("import %q: cannot import absolute path", path)
|
||||
}
|
||||
// Determine directory from import path.
|
||||
if ctxt.GOROOT != "" {
|
||||
dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", path)
|
||||
isDir := ctxt.isDir(dir)
|
||||
binaryOnly = !isDir && mode&AllowBinary != 0 && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
|
||||
if isDir || binaryOnly {
|
||||
p.Dir = dir
|
||||
p.Goroot = true
|
||||
p.Root = ctxt.GOROOT
|
||||
goto Found
|
||||
}
|
||||
}
|
||||
for _, root := range ctxt.gopath() {
|
||||
dir := ctxt.joinPath(root, "src", path)
|
||||
isDir := ctxt.isDir(dir)
|
||||
binaryOnly = !isDir && mode&AllowBinary != 0 && ctxt.isFile(ctxt.joinPath(root, pkga))
|
||||
if isDir || binaryOnly {
|
||||
p.Dir = dir
|
||||
p.Root = root
|
||||
goto Found
|
||||
}
|
||||
}
|
||||
return p, fmt.Errorf("import %q: cannot find package", path)
|
||||
}
|
||||
|
||||
Found:
|
||||
if p.Root != "" {
|
||||
if p.Goroot {
|
||||
p.SrcRoot = ctxt.joinPath(p.Root, "src", "pkg")
|
||||
} else {
|
||||
p.SrcRoot = ctxt.joinPath(p.Root, "src")
|
||||
}
|
||||
p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
|
||||
p.BinDir = ctxt.joinPath(p.Root, "bin")
|
||||
p.PkgObj = ctxt.joinPath(p.Root, pkga)
|
||||
}
|
||||
|
||||
if mode&FindOnly != 0 {
|
||||
return p, nil
|
||||
}
|
||||
if binaryOnly && (mode&AllowBinary) != 0 {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
dirs, err := ctxt.readDir(p.Dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return p, err
|
||||
}
|
||||
|
||||
var Sfiles []string // files with ".S" (capital S)
|
||||
var di DirInfo
|
||||
var firstFile string
|
||||
imported := make(map[string][]token.Position)
|
||||
testImported := make(map[string][]token.Position)
|
||||
xTestImported := make(map[string][]token.Position)
|
||||
fset := token.NewFileSet()
|
||||
for _, d := range dirs {
|
||||
if d.IsDir() {
|
||||
@ -247,7 +517,11 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
||||
continue
|
||||
}
|
||||
|
||||
ext := path.Ext(name)
|
||||
i := strings.LastIndex(name, ".")
|
||||
if i < 0 {
|
||||
i = len(name)
|
||||
}
|
||||
ext := name[i:]
|
||||
switch ext {
|
||||
case ".go", ".c", ".s", ".h", ".S":
|
||||
// tentatively okay
|
||||
@ -256,9 +530,15 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
||||
continue
|
||||
}
|
||||
|
||||
filename, data, err := ctxt.readFile(dir, name)
|
||||
filename := ctxt.joinPath(p.Dir, name)
|
||||
f, err := ctxt.openFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return p, err
|
||||
}
|
||||
data, err := ioutil.ReadAll(f)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return p, fmt.Errorf("read %s: %v", filename, err)
|
||||
}
|
||||
|
||||
// Look for +build comments to accept or reject the file.
|
||||
@ -269,13 +549,13 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
||||
// Going to save the file. For non-Go files, can stop here.
|
||||
switch ext {
|
||||
case ".c":
|
||||
di.CFiles = append(di.CFiles, name)
|
||||
p.CFiles = append(p.CFiles, name)
|
||||
continue
|
||||
case ".h":
|
||||
di.HFiles = append(di.HFiles, name)
|
||||
p.HFiles = append(p.HFiles, name)
|
||||
continue
|
||||
case ".s":
|
||||
di.SFiles = append(di.SFiles, name)
|
||||
p.SFiles = append(p.SFiles, name)
|
||||
continue
|
||||
case ".S":
|
||||
Sfiles = append(Sfiles, name)
|
||||
@ -284,7 +564,7 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
||||
|
||||
pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return p, err
|
||||
}
|
||||
|
||||
pkg := string(pf.Name.Name)
|
||||
@ -293,22 +573,20 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
||||
}
|
||||
|
||||
isTest := strings.HasSuffix(name, "_test.go")
|
||||
isXTest := false
|
||||
if isTest && strings.HasSuffix(pkg, "_test") {
|
||||
isXTest = true
|
||||
pkg = pkg[:len(pkg)-len("_test")]
|
||||
}
|
||||
|
||||
if di.Package == "" {
|
||||
di.Package = pkg
|
||||
if p.Name == "" {
|
||||
p.Name = pkg
|
||||
firstFile = name
|
||||
} else if pkg != di.Package {
|
||||
return nil, fmt.Errorf("%s: found packages %s (%s) and %s (%s)", dir, di.Package, firstFile, pkg, name)
|
||||
} else if pkg != p.Name {
|
||||
return p, fmt.Errorf("found packages %s (%s) and %s (%s) in %s", p.Name, firstFile, pkg, name, p.Dir)
|
||||
}
|
||||
if pf.Doc != nil {
|
||||
if di.PackageComment != nil {
|
||||
di.PackageComment.List = append(di.PackageComment.List, pf.Doc.List...)
|
||||
} else {
|
||||
di.PackageComment = pf.Doc
|
||||
}
|
||||
if pf.Doc != nil && p.Doc == "" {
|
||||
p.Doc = doc.Synopsis(pf.Doc.Text())
|
||||
}
|
||||
|
||||
// Record imports and information about cgo.
|
||||
@ -328,22 +606,24 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
||||
if err != nil {
|
||||
log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
|
||||
}
|
||||
if isTest {
|
||||
if isXTest {
|
||||
xTestImported[path] = append(xTestImported[path], fset.Position(spec.Pos()))
|
||||
} else if isTest {
|
||||
testImported[path] = append(testImported[path], fset.Position(spec.Pos()))
|
||||
} else {
|
||||
imported[path] = append(imported[path], fset.Position(spec.Pos()))
|
||||
}
|
||||
if path == "C" {
|
||||
if isTest {
|
||||
return nil, fmt.Errorf("%s: use of cgo in test not supported", filename)
|
||||
return p, fmt.Errorf("use of cgo in test %s not supported", filename)
|
||||
}
|
||||
cg := spec.Doc
|
||||
if cg == nil && len(d.Specs) == 1 {
|
||||
cg = d.Doc
|
||||
}
|
||||
if cg != nil {
|
||||
if err := ctxt.saveCgo(filename, &di, cg); err != nil {
|
||||
return nil, err
|
||||
if err := ctxt.saveCgo(filename, p, cg); err != nil {
|
||||
return p, err
|
||||
}
|
||||
}
|
||||
isCgo = true
|
||||
@ -352,48 +632,52 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
||||
}
|
||||
if isCgo {
|
||||
if ctxt.CgoEnabled {
|
||||
di.CgoFiles = append(di.CgoFiles, name)
|
||||
p.CgoFiles = append(p.CgoFiles, name)
|
||||
}
|
||||
} else if isXTest {
|
||||
p.XTestGoFiles = append(p.XTestGoFiles, name)
|
||||
} else if isTest {
|
||||
if pkg == string(pf.Name.Name) {
|
||||
di.TestGoFiles = append(di.TestGoFiles, name)
|
||||
} else {
|
||||
di.XTestGoFiles = append(di.XTestGoFiles, name)
|
||||
}
|
||||
p.TestGoFiles = append(p.TestGoFiles, name)
|
||||
} else {
|
||||
di.GoFiles = append(di.GoFiles, name)
|
||||
p.GoFiles = append(p.GoFiles, name)
|
||||
}
|
||||
}
|
||||
if di.Package == "" {
|
||||
return nil, fmt.Errorf("%s: no Go source files", dir)
|
||||
}
|
||||
di.Imports = make([]string, len(imported))
|
||||
di.ImportPos = imported
|
||||
i := 0
|
||||
for p := range imported {
|
||||
di.Imports[i] = p
|
||||
i++
|
||||
}
|
||||
di.TestImports = make([]string, len(testImported))
|
||||
di.TestImportPos = testImported
|
||||
i = 0
|
||||
for p := range testImported {
|
||||
di.TestImports[i] = p
|
||||
i++
|
||||
if p.Name == "" {
|
||||
return p, fmt.Errorf("no Go source files in %s", p.Dir)
|
||||
}
|
||||
|
||||
p.Imports, p.ImportPos = cleanImports(imported)
|
||||
p.TestImports, p.TestImportPos = cleanImports(testImported)
|
||||
p.XTestImports, p.XTestImportPos = cleanImports(xTestImported)
|
||||
|
||||
// add the .S files only if we are using cgo
|
||||
// (which means gcc will compile them).
|
||||
// The standard assemblers expect .s files.
|
||||
if len(di.CgoFiles) > 0 {
|
||||
di.SFiles = append(di.SFiles, Sfiles...)
|
||||
sort.Strings(di.SFiles)
|
||||
if len(p.CgoFiles) > 0 {
|
||||
p.SFiles = append(p.SFiles, Sfiles...)
|
||||
sort.Strings(p.SFiles)
|
||||
}
|
||||
|
||||
// File name lists are sorted because ReadDir sorts.
|
||||
sort.Strings(di.Imports)
|
||||
sort.Strings(di.TestImports)
|
||||
return &di, nil
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) {
|
||||
all := make([]string, 0, len(m))
|
||||
for path := range m {
|
||||
all = append(all, path)
|
||||
}
|
||||
sort.Strings(all)
|
||||
return all, m
|
||||
}
|
||||
|
||||
// Import is shorthand for Default.Import.
|
||||
func Import(path, src string, mode ImportMode) (*Package, error) {
|
||||
return Default.Import(path, src, mode)
|
||||
}
|
||||
|
||||
// ImportDir is shorthand for Default.ImportDir.
|
||||
func ImportDir(dir string, mode ImportMode) (*Package, error) {
|
||||
return Default.ImportDir(dir, mode)
|
||||
}
|
||||
|
||||
var slashslash = []byte("//")
|
||||
@ -473,7 +757,7 @@ func (ctxt *Context) shouldBuild(content []byte) bool {
|
||||
//
|
||||
// TODO(rsc): This duplicates code in cgo.
|
||||
// Once the dust settles, remove this code from cgo.
|
||||
func (ctxt *Context) saveCgo(filename string, di *DirInfo, cg *ast.CommentGroup) error {
|
||||
func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
|
||||
text := cg.Text()
|
||||
for _, line := range strings.Split(text, "\n") {
|
||||
orig := line
|
||||
@ -711,14 +995,11 @@ func init() {
|
||||
// ToolDir is the directory containing build tools.
|
||||
var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
|
||||
|
||||
// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
|
||||
// Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
|
||||
func isLocalPath(s string) bool {
|
||||
const sep = string(filepath.Separator)
|
||||
return s == "." || s == ".." ||
|
||||
filepath.HasPrefix(s, sep) ||
|
||||
filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
|
||||
filepath.VolumeName(s) != ""
|
||||
// IsLocalImport reports whether the import path is
|
||||
// a local import path, like ".", "..", "./foo", or "../foo".
|
||||
func IsLocalImport(path string) bool {
|
||||
return path == "." || path == ".." ||
|
||||
strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
|
||||
}
|
||||
|
||||
// ArchChar returns the architecture character for the given goarch.
|
||||
|
@ -5,83 +5,14 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func sortstr(x []string) []string {
|
||||
sort.Strings(x)
|
||||
return x
|
||||
}
|
||||
|
||||
var buildPkgs = []struct {
|
||||
dir string
|
||||
info *DirInfo
|
||||
}{
|
||||
{
|
||||
"go/build/pkgtest",
|
||||
&DirInfo{
|
||||
GoFiles: []string{"pkgtest.go"},
|
||||
SFiles: []string{"sqrt_" + runtime.GOARCH + ".s"},
|
||||
Package: "pkgtest",
|
||||
Imports: []string{"bytes"},
|
||||
TestImports: []string{"fmt", "pkgtest"},
|
||||
TestGoFiles: sortstr([]string{"sqrt_test.go", "sqrt_" + runtime.GOARCH + "_test.go"}),
|
||||
XTestGoFiles: []string{"xsqrt_test.go"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"go/build/cmdtest",
|
||||
&DirInfo{
|
||||
GoFiles: []string{"main.go"},
|
||||
Package: "main",
|
||||
Imports: []string{"go/build/pkgtest"},
|
||||
TestImports: []string{},
|
||||
},
|
||||
},
|
||||
{
|
||||
"go/build/cgotest",
|
||||
&DirInfo{
|
||||
CgoFiles: ifCgo([]string{"cgotest.go"}),
|
||||
CFiles: []string{"cgotest.c"},
|
||||
HFiles: []string{"cgotest.h"},
|
||||
Imports: []string{"C", "unsafe"},
|
||||
TestImports: []string{},
|
||||
Package: "cgotest",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func ifCgo(x []string) []string {
|
||||
if DefaultContext.CgoEnabled {
|
||||
return x
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestBuild(t *testing.T) {
|
||||
for _, tt := range buildPkgs {
|
||||
tree := Path[0] // Goroot
|
||||
dir := filepath.Join(tree.SrcDir(), tt.dir)
|
||||
info, err := ScanDir(dir)
|
||||
if err != nil {
|
||||
t.Errorf("ScanDir(%#q): %v", tt.dir, err)
|
||||
continue
|
||||
}
|
||||
// Don't bother testing import positions.
|
||||
tt.info.ImportPos, tt.info.TestImportPos = info.ImportPos, info.TestImportPos
|
||||
if !reflect.DeepEqual(info, tt.info) {
|
||||
t.Errorf("ScanDir(%#q) = %#v, want %#v\n", tt.dir, info, tt.info)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatch(t *testing.T) {
|
||||
ctxt := DefaultContext
|
||||
ctxt := Default
|
||||
what := "default"
|
||||
match := func(tag string) {
|
||||
if !ctxt.match(tag) {
|
||||
@ -106,3 +37,40 @@ func TestMatch(t *testing.T) {
|
||||
match(runtime.GOOS + "," + runtime.GOARCH + ",!bar")
|
||||
nomatch(runtime.GOOS + "," + runtime.GOARCH + ",bar")
|
||||
}
|
||||
|
||||
func TestDotSlashImport(t *testing.T) {
|
||||
p, err := ImportDir("testdata/other", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(p.Imports) != 1 || p.Imports[0] != "./file" {
|
||||
t.Fatalf("testdata/other: Imports=%v, want [./file]", p.Imports)
|
||||
}
|
||||
|
||||
p1, err := Import("./file", "testdata/other", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if p1.Name != "file" {
|
||||
t.Fatalf("./file: Name=%q, want %q", p1.Name, "file")
|
||||
}
|
||||
dir := filepath.Clean("testdata/other/file") // Clean to use \ on Windows
|
||||
if p1.Dir != dir {
|
||||
t.Fatalf("./file: Dir=%q, want %q", p1.Name, dir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalDirectory(t *testing.T) {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p, err := ImportDir(cwd, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if p.ImportPath != "go/build" {
|
||||
t.Fatalf("ImportPath=%q, want %q", p.ImportPath, "go/build")
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
// 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.
|
||||
|
||||
int
|
||||
Add(int x, int y, int *sum)
|
||||
{
|
||||
sum = x+y;
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
// 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 cgotest
|
||||
|
||||
/*
|
||||
char* greeting = "hello, world";
|
||||
*/
|
||||
// #include "cgotest.h"
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
var Greeting = C.GoString(C.greeting)
|
||||
|
||||
func DoAdd(x, y int) (sum int) {
|
||||
C.Add(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&sum)))
|
||||
return
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
// 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.
|
||||
|
||||
extern int Add(int, int, int *);
|
@ -1,12 +0,0 @@
|
||||
// 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 "go/build/pkgtest"
|
||||
|
||||
func main() {
|
||||
pkgtest.Foo()
|
||||
print(int(pkgtest.Sqrt(9)))
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
// 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 build
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
|
||||
var Path []*Tree
|
||||
|
||||
// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
|
||||
type Tree struct {
|
||||
Path string
|
||||
Goroot bool
|
||||
}
|
||||
|
||||
func newTree(p string) (*Tree, error) {
|
||||
if !filepath.IsAbs(p) {
|
||||
return nil, errors.New("must be absolute")
|
||||
}
|
||||
ep, err := filepath.EvalSymlinks(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Tree{Path: ep}, nil
|
||||
}
|
||||
|
||||
// SrcDir returns the tree's package source directory.
|
||||
func (t *Tree) SrcDir() string {
|
||||
if t.Goroot {
|
||||
return filepath.Join(t.Path, "src", "pkg")
|
||||
}
|
||||
return filepath.Join(t.Path, "src")
|
||||
}
|
||||
|
||||
// PkgDir returns the tree's package object directory.
|
||||
func (t *Tree) PkgDir() string {
|
||||
goos, goarch := runtime.GOOS, runtime.GOARCH
|
||||
if e := os.Getenv("GOOS"); e != "" {
|
||||
goos = e
|
||||
}
|
||||
if e := os.Getenv("GOARCH"); e != "" {
|
||||
goarch = e
|
||||
}
|
||||
return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
|
||||
}
|
||||
|
||||
// BinDir returns the tree's binary executable directory.
|
||||
func (t *Tree) BinDir() string {
|
||||
if t.Goroot {
|
||||
if gobin := os.Getenv("GOBIN"); gobin != "" {
|
||||
return filepath.Clean(gobin)
|
||||
}
|
||||
}
|
||||
return filepath.Join(t.Path, "bin")
|
||||
}
|
||||
|
||||
// HasSrc returns whether the given package's
|
||||
// source can be found inside this Tree.
|
||||
func (t *Tree) HasSrc(pkg string) bool {
|
||||
fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return fi.IsDir()
|
||||
}
|
||||
|
||||
// HasPkg returns whether the given package's
|
||||
// object file can be found inside this Tree.
|
||||
func (t *Tree) HasPkg(pkg string) bool {
|
||||
fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return !fi.IsDir()
|
||||
}
|
||||
|
||||
var (
|
||||
ErrNotFound = errors.New("package could not be found locally")
|
||||
ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
|
||||
)
|
||||
|
||||
// FindTree takes an import or filesystem path and returns the
|
||||
// tree where the package source should be and the package import path.
|
||||
func FindTree(path string) (tree *Tree, pkg string, err error) {
|
||||
if isLocalPath(path) {
|
||||
if path, err = filepath.Abs(path); err != nil {
|
||||
return
|
||||
}
|
||||
if path, err = filepath.EvalSymlinks(path); err != nil {
|
||||
return
|
||||
}
|
||||
for _, t := range Path {
|
||||
tpath := t.SrcDir() + string(filepath.Separator)
|
||||
if !filepath.HasPrefix(path, tpath) {
|
||||
continue
|
||||
}
|
||||
tree = t
|
||||
pkg = filepath.ToSlash(path[len(tpath):])
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("path %q not inside a GOPATH", path)
|
||||
return
|
||||
}
|
||||
tree = defaultTree
|
||||
pkg = filepath.ToSlash(path)
|
||||
for _, t := range Path {
|
||||
if t.HasSrc(pkg) {
|
||||
tree = t
|
||||
return
|
||||
}
|
||||
}
|
||||
if tree == nil {
|
||||
err = ErrTreeNotFound
|
||||
} else {
|
||||
err = ErrNotFound
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
// argument lists used by the build's gc and ld methods
|
||||
gcImportArgs []string
|
||||
ldImportArgs []string
|
||||
|
||||
// default tree for remote packages
|
||||
defaultTree *Tree
|
||||
)
|
||||
|
||||
// set up Path: parse and validate GOROOT and GOPATH variables
|
||||
func init() {
|
||||
root := runtime.GOROOT()
|
||||
t, err := newTree(root)
|
||||
if err == nil {
|
||||
t.Goroot = true
|
||||
Path = []*Tree{t}
|
||||
}
|
||||
|
||||
for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
|
||||
if p == "" {
|
||||
continue
|
||||
}
|
||||
t, err := newTree(p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
Path = append(Path, t)
|
||||
gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
|
||||
ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())
|
||||
|
||||
// select first GOPATH entry as default
|
||||
if defaultTree == nil {
|
||||
defaultTree = t
|
||||
}
|
||||
}
|
||||
|
||||
// use GOROOT if no valid GOPATH specified
|
||||
if defaultTree == nil && len(Path) > 0 {
|
||||
defaultTree = Path[0]
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
// 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 pkgtest
|
||||
|
||||
import "bytes"
|
||||
|
||||
func Foo() *bytes.Buffer {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Sqrt(x float64) float64
|
@ -1,10 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// func Sqrt(x float64) float64
|
||||
TEXT ·Sqrt(SB),7,$0
|
||||
FMOVD x+0(FP),F0
|
||||
FSQRT
|
||||
FMOVDP F0,r+8(FP)
|
||||
RET
|
@ -1 +0,0 @@
|
||||
package pkgtest
|
@ -1,9 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// func Sqrt(x float64) float64
|
||||
TEXT ·Sqrt(SB),7,$0
|
||||
SQRTSD x+0(FP), X0
|
||||
MOVSD X0, r+8(FP)
|
||||
RET
|
@ -1 +0,0 @@
|
||||
package pkgtest
|
@ -1,10 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// func Sqrt(x float64) float64
|
||||
TEXT ·Sqrt(SB),7,$0
|
||||
MOVD x+0(FP),F0
|
||||
SQRTD F0,F0
|
||||
MOVD F0,r+8(FP)
|
||||
RET
|
@ -1 +0,0 @@
|
||||
package pkgtest
|
@ -1,9 +0,0 @@
|
||||
// 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 pkgtest
|
||||
|
||||
import "fmt"
|
||||
|
||||
var _ = fmt.Printf
|
@ -1,9 +0,0 @@
|
||||
// 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 pkgtest_test
|
||||
|
||||
import "pkgtest"
|
||||
|
||||
var _ = pkgtest.Foo
|
@ -55,7 +55,7 @@ var tests = []GoodFileTest{
|
||||
|
||||
func TestGoodOSArch(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
if DefaultContext.goodOSArchFile(test.name) != test.result {
|
||||
if Default.goodOSArchFile(test.name) != test.result {
|
||||
t.Fatalf("goodOSArchFile(%q) != %v", test.name, test.result)
|
||||
}
|
||||
}
|
||||
|
5
src/pkg/go/build/testdata/other/file/file.go
vendored
Normal file
5
src/pkg/go/build/testdata/other/file/file.go
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
// Test data - not compiled.
|
||||
|
||||
package file
|
||||
|
||||
func F() {}
|
11
src/pkg/go/build/testdata/other/main.go
vendored
Normal file
11
src/pkg/go/build/testdata/other/main.go
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
// Test data - not compiled.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"./file"
|
||||
)
|
||||
|
||||
func main() {
|
||||
file.F()
|
||||
}
|
Loading…
Reference in New Issue
Block a user