github.phpd.cn/thought-machine/please@v12.2.0+incompatible/tools/please_go_test/gotest/find_cover_vars.go (about) 1 // Package gotest contains utilities used by plz_go_test. 2 package gotest 3 4 import ( 5 "go/build" 6 "io/ioutil" 7 "path" 8 "path/filepath" 9 "strings" 10 11 "gopkg.in/op/go-logging.v1" 12 13 "fs" 14 ) 15 16 var log = logging.MustGetLogger("buildgo") 17 18 // A CoverVar is just a combination of package path and variable name 19 // for one of the templated-in coverage variables. 20 type CoverVar struct { 21 Dir, ImportPath, ImportName, Var, File string 22 } 23 24 // FindCoverVars searches the given directory recursively to find all Go files with coverage variables. 25 func FindCoverVars(dir string, exclude, srcs []string) ([]CoverVar, error) { 26 if dir == "" { 27 return nil, nil 28 } 29 excludeMap := map[string]struct{}{} 30 for _, e := range exclude { 31 excludeMap[e] = struct{}{} 32 } 33 ret := []CoverVar{} 34 35 err := fs.Walk(dir, func(name string, isDir bool) error { 36 if _, present := excludeMap[name]; present { 37 if isDir { 38 return filepath.SkipDir 39 } 40 } else if strings.HasSuffix(name, ".a") && !strings.ContainsRune(path.Base(name), '#') { 41 vars, err := findCoverVars(name, srcs) 42 if err != nil { 43 return err 44 } 45 for _, v := range vars { 46 ret = append(ret, v) 47 } 48 } 49 return nil 50 }) 51 return ret, err 52 } 53 54 // findCoverVars scans a directory containing a .a file for any go files. 55 func findCoverVars(filepath string, srcs []string) ([]CoverVar, error) { 56 dir, file := path.Split(filepath) 57 dir = strings.TrimRight(dir, "/") 58 fi, err := ioutil.ReadDir(dir) 59 if err != nil { 60 return nil, err 61 } 62 importPath := collapseFinalDir(strings.TrimPrefix(strings.TrimSuffix(filepath, ".a"), "src/")) 63 ret := make([]CoverVar, 0, len(fi)) 64 for _, info := range fi { 65 name := info.Name() 66 if name != file && strings.HasSuffix(name, ".a") { 67 log.Warning("multiple .a files in %s, can't determine coverage variables accurately", dir) 68 return nil, nil 69 } else if strings.HasSuffix(name, ".go") && !info.IsDir() && !contains(path.Join(dir, name), srcs) { 70 if ok, err := build.Default.MatchFile(dir, name); ok && err == nil { 71 // N.B. The scheme here must match what we do in go_rules.build_defs 72 v := "GoCover_" + strings.Replace(name, ".", "_", -1) 73 ret = append(ret, coverVar(dir, importPath, v)) 74 } 75 } 76 } 77 return ret, nil 78 } 79 80 func contains(needle string, haystack []string) bool { 81 for _, straw := range haystack { 82 if straw == needle { 83 return true 84 } 85 } 86 return false 87 } 88 89 func coverVar(dir, importPath, v string) CoverVar { 90 log.Info("Found cover variable: %s %s %s", dir, importPath, v) 91 f := path.Join(dir, strings.TrimPrefix(v, "GoCover_")) 92 if strings.HasSuffix(f, "_go") { 93 f = f[:len(f)-3] + ".go" 94 } 95 return CoverVar{ 96 Dir: dir, 97 ImportPath: importPath, 98 Var: v, 99 File: f, 100 } 101 } 102 103 // collapseFinalDir mimics what go does with import paths; if the final two components of 104 // the given path are the same (eg. "src/core/core") it collapses them into one ("src/core") 105 func collapseFinalDir(s string) string { 106 if path.Base(path.Dir(s)) == path.Base(s) { 107 return path.Dir(s) 108 } 109 return s 110 }