]> Cypherpunks repositories - gostls13.git/commitdiff
go/build: add ctxt.MatchFile
authorRuss Cox <rsc@golang.org>
Sun, 15 Sep 2013 15:29:47 +0000 (11:29 -0400)
committerRuss Cox <rsc@golang.org>
Sun, 15 Sep 2013 15:29:47 +0000 (11:29 -0400)
Fixes #6369.

R=dsymonds, r
CC=golang-dev
https://golang.org/cl/13708043

src/pkg/go/build/build.go
src/pkg/go/build/build_test.go

index be48df9d38be82e5c35a0923927efc4abd118117..d608f0410ec91f9174d05d9b4096733bf798b9ce 100644 (file)
@@ -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
index e36048edec925aa368c1843ccee8d2d24958639e..fca8d4bdb27d42da2cdc380d52b129439fd56a21 100644 (file)
@@ -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)
+               }
+       }
+}