Commit aa53b37f authored by Russ Cox's avatar Russ Cox

go/build: add ctxt.MatchFile

Fixes #6369.

R=dsymonds, r
CC=golang-dev
https://golang.org/cl/13708043
parent 1385e394
......@@ -408,6 +408,14 @@ func (e *NoGoError) Error() string {
return "no buildable Go source files in " + e.Dir
}
func nameExt(name string) string {
i := strings.LastIndex(name, ".")
if i < 0 {
return ""
}
return name[i:]
}
// Import returns details about the Go package named by the import path,
// interpreting local import paths relative to the srcDir directory.
// If the path is a local import path naming a package that can be imported
......@@ -591,58 +599,15 @@ Found:
if d.IsDir() {
continue
}
name := d.Name()
if strings.HasPrefix(name, "_") ||
strings.HasPrefix(name, ".") {
continue
}
i := strings.LastIndex(name, ".")
if i < 0 {
i = len(name)
}
ext := name[i:]
if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles {
if ext == ".go" {
p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
}
continue
}
switch ext {
case ".go", ".c", ".cc", ".cxx", ".cpp", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
// tentatively okay - read to make sure
case ".syso":
// binary objects to add to package archive
// Likely of the form foo_windows.syso, but
// the name was vetted above with goodOSArchFile.
p.SysoFiles = append(p.SysoFiles, name)
continue
default:
// skip
continue
}
name := d.Name()
ext := nameExt(name)
filename := ctxt.joinPath(p.Dir, name)
f, err := ctxt.openFile(filename)
match, data, filename, err := ctxt.matchFile(p.Dir, name, true, allTags)
if err != nil {
return p, err
}
var data []byte
if strings.HasSuffix(filename, ".go") {
data, err = readImports(f, false)
} else {
data, err = readComments(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.
if !ctxt.shouldBuild(data, allTags) && !ctxt.UseAllFiles {
if !match {
if ext == ".go" {
p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
}
......@@ -672,6 +637,12 @@ Found:
case ".swigcxx":
p.SwigCXXFiles = append(p.SwigCXXFiles, name)
continue
case ".syso":
// binary objects to add to package archive
// Likely of the form foo_windows.syso, but
// the name was vetted above with goodOSArchFile.
p.SysoFiles = append(p.SysoFiles, name)
continue
}
pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
......@@ -782,6 +753,79 @@ Found:
return p, pkgerr
}
// MatchFile reports whether the file with the given name in the given directory
// matches the context and would be included in a Package created by ImportDir
// of that directory.
//
// MatchFile considers the name of the file and may use ctxt.OpenFile to
// read some or all of the file's content.
func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) {
match, _, _, err = ctxt.matchFile(dir, name, false, nil)
return
}
// matchFile determines whether the file with the given name in the given directory
// should be included in the package being constructed.
// It returns the data read from the file.
// If returnImports is true and name denotes a Go program, matchFile reads
// until the end of the imports (and returns that data) even though it only
// considers text until the first non-comment.
// If allTags is non-nil, matchFile records any encountered build tag
// by setting allTags[tag] = true.
func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map[string]bool) (match bool, data []byte, filename string, err error) {
if strings.HasPrefix(name, "_") ||
strings.HasPrefix(name, ".") {
return
}
i := strings.LastIndex(name, ".")
if i < 0 {
i = len(name)
}
ext := name[i:]
if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles {
return
}
switch ext {
case ".go", ".c", ".cc", ".cxx", ".cpp", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
// tentatively okay - read to make sure
case ".syso":
// binary, no reading
match = true
return
default:
// skip
return
}
filename = ctxt.joinPath(dir, name)
f, err := ctxt.openFile(filename)
if err != nil {
return
}
if strings.HasSuffix(filename, ".go") {
data, err = readImports(f, false)
} else {
data, err = readComments(f)
}
f.Close()
if err != nil {
err = fmt.Errorf("read %s: %v", filename, err)
return
}
// Look for +build comments to accept or reject the file.
if !ctxt.shouldBuild(data, allTags) && !ctxt.UseAllFiles {
return
}
match = true
return
}
func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) {
all := make([]string, 0, len(m))
for path := range m {
......@@ -1114,16 +1158,22 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
}
n := len(l)
if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
allTags[l[n-2]] = true
allTags[l[n-1]] = true
if allTags != nil {
allTags[l[n-2]] = true
allTags[l[n-1]] = true
}
return l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH
}
if n >= 1 && knownOS[l[n-1]] {
allTags[l[n-1]] = true
if allTags != nil {
allTags[l[n-1]] = true
}
return l[n-1] == ctxt.GOOS
}
if n >= 1 && knownArch[l[n-1]] {
allTags[l[n-1]] = true
if allTags != nil {
allTags[l[n-1]] = true
}
return l[n-1] == ctxt.GOARCH
}
return true
......
......@@ -5,10 +5,12 @@
package build
import (
"io"
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"testing"
)
......@@ -142,3 +144,43 @@ func TestShouldBuild(t *testing.T) {
t.Errorf("shoudBuild(file3) tags = %v, want %v", m, want3)
}
}
type readNopCloser struct {
io.Reader
}
func (r readNopCloser) Close() error {
return nil
}
var matchFileTests = []struct {
name string
data string
match bool
}{
{"foo_arm.go", "", true},
{"foo1_arm.go", "// +build linux\n\npackage main\n", false},
{"foo_darwin.go", "", false},
{"foo.go", "", true},
{"foo1.go", "// +build linux\n\npackage main\n", false},
{"foo.badsuffix", "", false},
}
func TestMatchFile(t *testing.T) {
for _, tt := range matchFileTests {
ctxt := Context{GOARCH: "arm", GOOS: "plan9"}
ctxt.OpenFile = func(path string) (r io.ReadCloser, err error) {
if path != "x+"+tt.name {
t.Fatalf("OpenFile asked for %q, expected %q", path, "x+"+tt.name)
}
return &readNopCloser{strings.NewReader(tt.data)}, nil
}
ctxt.JoinPath = func(elem ...string) string {
return strings.Join(elem, "+")
}
match, err := ctxt.MatchFile("x", tt.name)
if match != tt.match || err != nil {
t.Fatalf("MatchFile(%q) = %v, %v, want %v, nil", tt.name, match, err, tt.match)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment