mirror of
https://github.com/golang/go
synced 2024-11-18 12:54:44 -07:00
go.tools/go/buildutil: more utilities.
- ParseFile (core of go/loader's parseFiles(); also used by refactor/rename) - ContainingPackage (core of Oracle's guessImportPath; also used by refactor/rename) - Accessors for effective "methods" of build.Context: FileExists, OpenFile, IsAbsPath, JoinPath. LGTM=sameer R=dave, sameer CC=golang-codereviews, gri https://golang.org/cl/146120043
This commit is contained in:
parent
c90cb9e042
commit
aba8625c37
127
go/buildutil/util.go
Normal file
127
go/buildutil/util.go
Normal file
@ -0,0 +1,127 @@
|
||||
// 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 buildutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseFile behaves like parser.ParseFile,
|
||||
// but uses the build context's virtual file system, if any.
|
||||
//
|
||||
// If file is not absolute (as defined by IsAbsPath), the (dir, file)
|
||||
// components are joined using JoinPath; dir must be absolute.
|
||||
//
|
||||
// The displayPath function, if provided, is used to transform the
|
||||
// filename that will be attached to the ASTs.
|
||||
//
|
||||
// TODO(adonovan): call this from go/loader.parseFiles when the tree thaws.
|
||||
//
|
||||
func ParseFile(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, file string, mode parser.Mode) (*ast.File, error) {
|
||||
if !IsAbsPath(ctxt, file) {
|
||||
file = JoinPath(ctxt, dir, file)
|
||||
}
|
||||
rd, err := OpenFile(ctxt, file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rd.Close() // ignore error
|
||||
if displayPath != nil {
|
||||
file = displayPath(file)
|
||||
}
|
||||
return parser.ParseFile(fset, file, rd, mode)
|
||||
}
|
||||
|
||||
// ContainingPackage returns the package containing filename.
|
||||
//
|
||||
// If filename is not absolute, it is interpreted relative to working directory dir.
|
||||
// All I/O is via the build context's virtual file system, if any.
|
||||
//
|
||||
// The '...Files []string' fields of the resulting build.Package are not
|
||||
// populated (build.FindOnly mode).
|
||||
//
|
||||
// TODO(adonovan): call this from oracle when the tree thaws.
|
||||
//
|
||||
func ContainingPackage(ctxt *build.Context, dir, filename string) (*build.Package, error) {
|
||||
if !IsAbsPath(ctxt, filename) {
|
||||
filename = JoinPath(ctxt, dir, filename)
|
||||
}
|
||||
|
||||
// We must not assume the virtualized file tree uses
|
||||
// "/" always,
|
||||
// `\` always,
|
||||
// or os.PathSeparator (which varies by platform),
|
||||
// but to make any progress, we are forced to assume that
|
||||
// virtualized paths will not use `\` unless the PathSeparator
|
||||
// is also `\`, thus we can rely on filepath.ToSlash for some sanity.
|
||||
|
||||
dirSlash := path.Dir(filepath.ToSlash(filename)) + "/"
|
||||
|
||||
// We assume that no source root (GOPATH[i] or GOROOT) contains any other.
|
||||
for _, srcdir := range ctxt.SrcDirs() {
|
||||
srcdirSlash := filepath.ToSlash(srcdir) + "/"
|
||||
if strings.HasPrefix(dirSlash, srcdirSlash) {
|
||||
importPath := dirSlash[len(srcdirSlash) : len(dirSlash)-len("/")]
|
||||
return ctxt.Import(importPath, dir, build.FindOnly)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("can't find package containing %s", filename)
|
||||
}
|
||||
|
||||
// -- Effective methods of virtual file system -------------------------
|
||||
|
||||
// FileExists returns true if the specified file exists,
|
||||
// using the build context's virtual file system.
|
||||
func FileExists(ctxt *build.Context, path string) bool {
|
||||
if ctxt.OpenFile != nil {
|
||||
r, err := ctxt.OpenFile(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
r.Close() // ignore error
|
||||
return true
|
||||
}
|
||||
_, err := os.Stat(path)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// OpenFile behaves like os.Open,
|
||||
// but uses the build context's virtual file system, if any.
|
||||
func OpenFile(ctxt *build.Context, path string) (io.ReadCloser, error) {
|
||||
if ctxt.OpenFile != nil {
|
||||
return ctxt.OpenFile(path)
|
||||
}
|
||||
return os.Open(path)
|
||||
}
|
||||
|
||||
// IsAbsPath behaves like filepath.IsAbs,
|
||||
// but uses the build context's virtual file system, if any.
|
||||
func IsAbsPath(ctxt *build.Context, path string) bool {
|
||||
if ctxt.IsAbsPath != nil {
|
||||
return ctxt.IsAbsPath(path)
|
||||
}
|
||||
return filepath.IsAbs(path)
|
||||
}
|
||||
|
||||
// JoinPath behaves like filepath.Join,
|
||||
// but uses the build context's virtual file system.
|
||||
func JoinPath(ctxt *build.Context, path ...string) string {
|
||||
if ctxt.JoinPath != nil {
|
||||
return ctxt.JoinPath(path...)
|
||||
}
|
||||
return filepath.Join(path...)
|
||||
}
|
||||
|
||||
// TODO(adonovan): SplitPathList, IsDir, HasSubdir, ReadDir?
|
41
go/buildutil/util_test.go
Normal file
41
go/buildutil/util_test.go
Normal file
@ -0,0 +1,41 @@
|
||||
// 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 buildutil_test
|
||||
|
||||
import (
|
||||
"go/build"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"code.google.com/p/go.tools/go/buildutil"
|
||||
)
|
||||
|
||||
func TestContainingPackage(t *testing.T) {
|
||||
// unvirtualized:
|
||||
goroot := runtime.GOROOT()
|
||||
gopath := filepath.SplitList(os.Getenv("GOPATH"))[0]
|
||||
|
||||
for _, test := range [][2]string{
|
||||
{goroot + "/src/fmt/print.go", "fmt"},
|
||||
{goroot + "/src/encoding/json/foo.go", "encoding/json"},
|
||||
{goroot + "/src/encoding/missing/foo.go", "(not found)"},
|
||||
{gopath + "/src/code.google.com/p/go.tools/go/buildutil/util_test.go",
|
||||
"code.google.com/p/go.tools/go/buildutil"},
|
||||
} {
|
||||
file, want := test[0], test[1]
|
||||
bp, err := buildutil.ContainingPackage(&build.Default, ".", file)
|
||||
got := bp.ImportPath
|
||||
if err != nil {
|
||||
got = "(not found)"
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("ContainingPackage(%q) = %s, want %s", file, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(adonovan): test on virtualized GOPATH too.
|
||||
}
|
Loading…
Reference in New Issue
Block a user