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