diff options
Diffstat (limited to 'go/tools/builders/filter.go')
-rw-r--r-- | go/tools/builders/filter.go | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/go/tools/builders/filter.go b/go/tools/builders/filter.go new file mode 100644 index 00000000..fbb0f2ac --- /dev/null +++ b/go/tools/builders/filter.go @@ -0,0 +1,168 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "go/ast" + "go/build" + "go/token" + "os" + "path/filepath" + "strings" +) + +type fileInfo struct { + filename string + ext ext + header []byte + fset *token.FileSet + parsed *ast.File + parseErr error + matched bool + isCgo bool + pkg string + imports []fileImport + embeds []fileEmbed +} + +type ext int + +const ( + goExt ext = iota + cExt + cxxExt + objcExt + objcxxExt + sExt + hExt +) + +type fileImport struct { + path string + pos token.Pos + doc *ast.CommentGroup +} + +type fileEmbed struct { + pattern string + pos token.Position +} + +type archiveSrcs struct { + goSrcs, cSrcs, cxxSrcs, objcSrcs, objcxxSrcs, sSrcs, hSrcs []fileInfo +} + +// filterAndSplitFiles filters files using build constraints and collates +// them by extension. +func filterAndSplitFiles(fileNames []string) (archiveSrcs, error) { + var res archiveSrcs + for _, s := range fileNames { + src, err := readFileInfo(build.Default, s) + if err != nil { + return archiveSrcs{}, err + } + if !src.matched { + continue + } + var srcs *[]fileInfo + switch src.ext { + case goExt: + srcs = &res.goSrcs + case cExt: + srcs = &res.cSrcs + case cxxExt: + srcs = &res.cxxSrcs + case objcExt: + srcs = &res.objcSrcs + case objcxxExt: + srcs = &res.objcxxSrcs + case sExt: + srcs = &res.sSrcs + case hExt: + srcs = &res.hSrcs + } + *srcs = append(*srcs, src) + } + return res, nil +} + +// readFileInfo applies build constraints to an input file and returns whether +// it should be compiled. +func readFileInfo(bctx build.Context, input string) (fileInfo, error) { + fi := fileInfo{filename: input} + if ext := filepath.Ext(input); ext == ".C" { + fi.ext = cxxExt + } else { + switch strings.ToLower(ext) { + case ".go": + fi.ext = goExt + case ".c": + fi.ext = cExt + case ".cc", ".cxx", ".cpp": + fi.ext = cxxExt + case ".m": + fi.ext = objcExt + case ".mm": + fi.ext = objcxxExt + case ".s": + fi.ext = sExt + case ".h", ".hh", ".hpp", ".hxx": + fi.ext = hExt + default: + return fileInfo{}, fmt.Errorf("unrecognized file extension: %s", ext) + } + } + + dir, base := filepath.Split(input) + // Check build constraints on non-cgo files. + // Skip cgo files, since they get rejected (due to leading '_') and won't + // have any build constraints anyway. + if strings.HasPrefix(base, "_cgo") { + fi.matched = true + } else { + match, err := bctx.MatchFile(dir, base) + if err != nil { + return fi, err + } + fi.matched = match + } + // If it's not a go file, there's nothing more to read. + if fi.ext != goExt { + return fi, nil + } + + // Scan the file for imports and embeds. + f, err := os.Open(input) + if err != nil { + return fileInfo{}, err + } + defer f.Close() + fi.fset = token.NewFileSet() + if err := readGoInfo(f, &fi); err != nil { + return fileInfo{}, err + } + + // Exclude cgo files if cgo is not enabled. + for _, imp := range fi.imports { + if imp.path == "C" { + fi.isCgo = true + break + } + } + fi.matched = fi.matched && (bctx.CgoEnabled || !fi.isCgo) + + return fi, nil +} |