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 processCounterDataFile := func(cdf string, k int) error {
208 cf, err := os.Open(cdf)
209 if err != nil {
210 return r.fatal("opening counter data file %s: %s", cdf, err)
211 }
212 defer cf.Close()
213 var mr *MReader
214 mr, err = NewMreader(cf)
215 if err != nil {
216 return r.fatal("creating reader for counter data file %s: %s", cdf, err)
217 }
218 var cdr *decodecounter.CounterDataReader
219 cdr, err = decodecounter.NewCounterDataReader(cdf, mr)
220 if err != nil {
221 return r.fatal("reading counter data file %s: %s", cdf, err)
222 }
223 r.vis.BeginCounterDataFile(cdf, cdr, p.Origins[k])
224 var data decodecounter.FuncPayload
225 for {
226 ok, err := cdr.NextFunc(&data)
227 if err != nil {
228 return r.fatal("reading counter data file %s: %v", cdf, err)
229 }
230 if !ok {
231 break
232 }
233 r.vis.VisitFuncCounterData(data)
234 }
235 r.vis.EndCounterDataFile(cdf, cdr, p.Origins[k])
236 return nil
237 }
238
239
240 for k, cdf := range p.CounterDataFiles {
241 if err := processCounterDataFile(cdf, k); err != nil {
242 return err
243 }
244 }
245 r.vis.EndCounters()
246
247
248
249
250 np := uint32(mfr.NumPackages())
251 payload := []byte{}
252 for pkIdx := uint32(0); pkIdx < np; pkIdx++ {
253 var pd *decodemeta.CoverageMetaDataDecoder
254 pd, payload, err = mfr.GetPackageDecoder(pkIdx, payload)
255 if err != nil {
256 return r.fatal("reading pkg %d from meta-file %s: %s", pkIdx, p.MetaFile, err)
257 }
258 r.processPackage(p.MetaFile, pd, pkIdx)
259 }
260 r.vis.EndPod(p)
261
262 return nil
263 }
264
265 func (r *CovDataReader) processPackage(mfname string, pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) error {
266 if r.matchpkg != nil {
267 if !r.matchpkg(pd.PackagePath()) {
268 return nil
269 }
270 }
271 r.vis.BeginPackage(pd, pkgIdx)
272 nf := pd.NumFuncs()
273 var fd coverage.FuncDesc
274 for fidx := uint32(0); fidx < nf; fidx++ {
275 if err := pd.ReadFunc(fidx, &fd); err != nil {
276 return r.fatal("reading meta-data file %s: %v", mfname, err)
277 }
278 r.vis.VisitFunc(pkgIdx, fidx, &fd)
279 }
280 r.vis.EndPackage(pd, pkgIdx)
281 return nil
282 }
283
View as plain text