Make microfactory support go build tags
This is necessary to support other go code that uses build tags to control which files build on which platforms. For example, the github.com/golang/protobuf/proto package includes two implementations of pointer: pointer_reflect: // ... // +build appengine js // This file contains an implementation of proto field accesses using package reflect. // It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can // be used on App Engine. pointer_unsafe.go: // ... // +build !appengine,!js // This file contains the implementation of the proto field accesses using package unsafe. Without this change, microfactory tries to include both files, which breaks, since that enables multiple implementations of the same symbols. This implements the logic to find the +build comments (following the spirit of the functionality in go/build, even though they make different choices of parsers), and the logic to match the tags to the current system (which isn't exported as public API, so we have a simplified version). Since we're only parsing the comments before the import statement, this does not significantly affect performance. Test: Build github.com/golang/protobuf/proto Change-Id: I10c48472d3f9f3e96b800a5d7c15450b1737002b
This commit is contained in:
parent
18a0d2e9b5
commit
64c10381ad
1 changed files with 70 additions and 1 deletions
|
@ -47,6 +47,7 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
|
@ -199,6 +200,62 @@ func (p *GoPackage) FindDeps(config *Config, path string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Roughly equivalent to go/build.Context.match
|
||||
func matchBuildTag(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
}
|
||||
if i := strings.Index(name, ","); i >= 0 {
|
||||
ok1 := matchBuildTag(name[:i])
|
||||
ok2 := matchBuildTag(name[i+1:])
|
||||
return ok1 && ok2
|
||||
}
|
||||
if strings.HasPrefix(name, "!!") {
|
||||
return false
|
||||
}
|
||||
if strings.HasPrefix(name, "!") {
|
||||
return len(name) > 1 && !matchBuildTag(name[1:])
|
||||
}
|
||||
|
||||
if name == runtime.GOOS || name == runtime.GOARCH || name == "gc" {
|
||||
return true
|
||||
}
|
||||
for _, tag := range build.Default.BuildTags {
|
||||
if tag == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, tag := range build.Default.ReleaseTags {
|
||||
if tag == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func parseBuildComment(comment string) (matches, ok bool) {
|
||||
if !strings.HasPrefix(comment, "//") {
|
||||
return false, false
|
||||
}
|
||||
for i, c := range comment {
|
||||
if i < 2 || c == ' ' || c == '\t' {
|
||||
continue
|
||||
} else if c == '+' {
|
||||
f := strings.Fields(comment[i:])
|
||||
if f[0] == "+build" {
|
||||
matches = false
|
||||
for _, tok := range f[1:] {
|
||||
matches = matches || matchBuildTag(tok)
|
||||
}
|
||||
return matches, true
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
// findDeps is the recursive version of FindDeps. allPackages is the map of
|
||||
// all locally defined packages so that the same dependency of two different
|
||||
// packages is only resolved once.
|
||||
|
@ -217,7 +274,7 @@ func (p *GoPackage) findDeps(config *Config, path string, allPackages *linkedDep
|
|||
return false
|
||||
}
|
||||
return true
|
||||
}, parser.ImportsOnly)
|
||||
}, parser.ImportsOnly|parser.ParseComments)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error parsing directory %q: %v", path, err)
|
||||
}
|
||||
|
@ -236,6 +293,18 @@ func (p *GoPackage) findDeps(config *Config, path string, allPackages *linkedDep
|
|||
localDeps := make(map[string]bool)
|
||||
|
||||
for filename, astFile := range foundPkg.Files {
|
||||
ignore := false
|
||||
for _, commentGroup := range astFile.Comments {
|
||||
for _, comment := range commentGroup.List {
|
||||
if matches, ok := parseBuildComment(comment.Text); ok && !matches {
|
||||
ignore = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if ignore {
|
||||
continue
|
||||
}
|
||||
|
||||
p.files = append(p.files, filename)
|
||||
|
||||
for _, importSpec := range astFile.Imports {
|
||||
|
|
Loading…
Reference in a new issue