1
2
3
4
5 package cov
6
7 import (
8 "cmd/internal/bio"
9 "fmt"
10 "internal/coverage"
11 "internal/coverage/decodecounter"
12 "internal/coverage/decodemeta"
13 "internal/coverage/pods"
14 "io"
15 "os"
16 )
17
18
19
20
21
22
23
24
25
26 type CovDataReader struct {
27 vis CovDataVisitor
28 indirs []string
29 matchpkg func(name string) bool
30 flags CovDataReaderFlags
31 err error
32 verbosityLevel int
33 }
34
35
36
37
38
39
40
41
42
43
44 func MakeCovDataReader(vis CovDataVisitor, indirs []string, verbosityLevel int, flags CovDataReaderFlags, matchpkg func(name string) bool) *CovDataReader {
45 return &CovDataReader{
46 vis: vis,
47 indirs: indirs,
48 matchpkg: matchpkg,
49 verbosityLevel: verbosityLevel,
50 flags: flags,
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 type CovDataVisitor interface {
86
87
88
89 BeginPod(p pods.Pod)
90 EndPod(p pods.Pod)
91
92
93
94
95 VisitMetaDataFile(mdf string, mfr *decodemeta.CoverageMetaFileReader)
96
97
98
99
100 BeginCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int)
101 EndCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int)
102
103
104 VisitFuncCounterData(payload decodecounter.FuncPayload)
105
106
107
108 EndCounters()
109
110
111
112
113 BeginPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32)
114 EndPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32)
115
116
117 VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc)
118
119
120 Finish()
121 }
122
123 type CovDataReaderFlags uint32
124
125 const (
126 CovDataReaderNoFlags CovDataReaderFlags = 0
127 PanicOnError = 1 << iota
128 PanicOnWarning
129 )
130
131 func (r *CovDataReader) Visit() error {
132 podlist, err := pods.CollectPods(r.indirs, false)
133 if err != nil {
134 return fmt.Errorf("reading inputs: %v", err)
135 }
136 if len(podlist) == 0 {
137 r.warn("no applicable files found in input directories")
138 }
139 for _, p := range podlist {
140 if err := r.visitPod(p); err != nil {
141 return err
142 }
143 }
144 r.vis.Finish()
145 return nil
146 }
147
148 func (r *CovDataReader) verb(vlevel int, s string, a ...interface{}) {
149 if r.verbosityLevel >= vlevel {
150 fmt.Fprintf(os.Stderr, s, a...)
151 fmt.Fprintf(os.Stderr, "\n")
152 }
153 }
154
155 func (r *CovDataReader) warn(s string, a ...interface{}) {
156 fmt.Fprintf(os.Stderr, "warning: ")
157 fmt.Fprintf(os.Stderr, s, a...)
158 fmt.Fprintf(os.Stderr, "\n")
159 if (r.flags & PanicOnWarning) != 0 {
160 panic("unexpected warning")
161 }
162 }
163
164 func (r *CovDataReader) fatal(s string, a ...interface{}) error {
165 if r.err != nil {
166 return nil
167 }
168 errstr := "error: " + fmt.Sprintf(s, a...) + "\n"
169 if (r.flags & PanicOnError) != 0 {
170 fmt.Fprintf(os.Stderr, "%s", errstr)
171 panic("fatal error")
172 }
173 r.err = fmt.Errorf("%s", errstr)
174 return r.err
175 }
176
177
178
179 func (r *CovDataReader) visitPod(p pods.Pod) error {
180 r.verb(1, "visiting pod: metafile %s with %d counter files",
181 p.MetaFile, len(p.CounterDataFiles))
182 r.vis.BeginPod(p)
183
184
185 f, err := os.Open(p.MetaFile)
186 if err != nil {
187 return r.fatal("unable to open meta-file %s", p.MetaFile)
188 }
189 defer f.Close()
190 br := bio.NewReader(f)
191 fi, err := f.Stat()
192 if err != nil {
193 return r.fatal("unable to stat metafile %s: %v", p.MetaFile, err)
194 }
195 fileView := br.SliceRO(uint64(fi.Size()))
196 br.MustSeek(0, io.SeekStart)
197
198 r.verb(1, "fileView for pod is length %d", len(fileView))
199
200 var mfr *decodemeta.CoverageMetaFileReader
201 mfr, err = decodemeta.NewCoverageMetaFileReader(f, fileView)
202 if err != nil {
203 return r.fatal("decoding meta-file %s: %s", p.MetaFile, err)
204 }
205 r.vis.VisitMetaDataFile(p.MetaFile, mfr)
206
207
208 for k, cdf := range p.CounterDataFiles {
209 cf, err := os.Open(cdf)
210 if err != nil {
211 return r.fatal("opening counter data file %s: %s", cdf, err)
212 }
213 defer func(f *os.File) {
214 f.Close()
215 }(cf)
216 var mr *MReader
217 mr, err = NewMreader(cf)
218 if err != nil {
219 return r.fatal("creating reader for counter data file %s: %s", cdf, err)
220 }
221 var cdr *decodecounter.CounterDataReader
222 cdr, err = decodecounter.NewCounterDataReader(cdf, mr)
223 if err != nil {
224 return r.fatal("reading counter data file %s: %s", cdf, err)
225 }
226 r.vis.BeginCounterDataFile(cdf, cdr, p.Origins[k])
227 var data decodecounter.FuncPayload
228 for {
229 ok, err := cdr.NextFunc(&data)
230 if err != nil {
231 return r.fatal("reading counter data file %s: %v", cdf, err)
232 }
233 if !ok {
234 break
235 }
236 r.vis.VisitFuncCounterData(data)
237 }
238 r.vis.EndCounterDataFile(cdf, cdr, p.Origins[k])
239 }
240 r.vis.EndCounters()
241
242
243
244
245 np := uint32(mfr.NumPackages())
246 payload := []byte{}
247 for pkIdx := uint32(0); pkIdx < np; pkIdx++ {
248 var pd *decodemeta.CoverageMetaDataDecoder
249 pd, payload, err = mfr.GetPackageDecoder(pkIdx, payload)
250 if err != nil {
251 return r.fatal("reading pkg %d from meta-file %s: %s", pkIdx, p.MetaFile, err)
252 }
253 r.processPackage(p.MetaFile, pd, pkIdx)
254 }
255 r.vis.EndPod(p)
256
257 return nil
258 }
259
260 func (r *CovDataReader) processPackage(mfname string, pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) error {
261 if r.matchpkg != nil {
262 if !r.matchpkg(pd.PackagePath()) {
263 return nil
264 }
265 }
266 r.vis.BeginPackage(pd, pkgIdx)
267 nf := pd.NumFuncs()
268 var fd coverage.FuncDesc
269 for fidx := uint32(0); fidx < nf; fidx++ {
270 if err := pd.ReadFunc(fidx, &fd); err != nil {
271 return r.fatal("reading meta-data file %s: %v", mfname, err)
272 }
273 r.vis.VisitFunc(pkgIdx, fidx, &fd)
274 }
275 r.vis.EndPackage(pd, pkgIdx)
276 return nil
277 }
278
View as plain text