| |
| |
| |
|
|
| package cov |
|
|
| import ( |
| "cmd/internal/bio" |
| "fmt" |
| "internal/coverage" |
| "internal/coverage/decodecounter" |
| "internal/coverage/decodemeta" |
| "internal/coverage/pods" |
| "io" |
| "os" |
| ) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| type CovDataReader struct { |
| vis CovDataVisitor |
| indirs []string |
| matchpkg func(name string) bool |
| flags CovDataReaderFlags |
| err error |
| verbosityLevel int |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| func MakeCovDataReader(vis CovDataVisitor, indirs []string, verbosityLevel int, flags CovDataReaderFlags, matchpkg func(name string) bool) *CovDataReader { |
| return &CovDataReader{ |
| vis: vis, |
| indirs: indirs, |
| matchpkg: matchpkg, |
| verbosityLevel: verbosityLevel, |
| flags: flags, |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| type CovDataVisitor interface { |
| |
| |
| |
| BeginPod(p pods.Pod) |
| EndPod(p pods.Pod) |
|
|
| |
| |
| |
| VisitMetaDataFile(mdf string, mfr *decodemeta.CoverageMetaFileReader) |
|
|
| |
| |
| |
| BeginCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) |
| EndCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) |
|
|
| |
| VisitFuncCounterData(payload decodecounter.FuncPayload) |
|
|
| |
| |
| EndCounters() |
|
|
| |
| |
| |
| BeginPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) |
| EndPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) |
|
|
| |
| VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc) |
|
|
| |
| Finish() |
| } |
|
|
| type CovDataReaderFlags uint32 |
|
|
| const ( |
| CovDataReaderNoFlags CovDataReaderFlags = 0 |
| PanicOnError = 1 << iota |
| PanicOnWarning |
| ) |
|
|
| func (r *CovDataReader) Visit() error { |
| podlist, err := pods.CollectPods(r.indirs, false) |
| if err != nil { |
| return fmt.Errorf("reading inputs: %v", err) |
| } |
| if len(podlist) == 0 { |
| r.warn("no applicable files found in input directories") |
| } |
| for _, p := range podlist { |
| if err := r.visitPod(p); err != nil { |
| return err |
| } |
| } |
| r.vis.Finish() |
| return nil |
| } |
|
|
| func (r *CovDataReader) verb(vlevel int, s string, a ...any) { |
| if r.verbosityLevel >= vlevel { |
| fmt.Fprintf(os.Stderr, s, a...) |
| fmt.Fprintf(os.Stderr, "\n") |
| } |
| } |
|
|
| func (r *CovDataReader) warn(s string, a ...any) { |
| fmt.Fprintf(os.Stderr, "warning: ") |
| fmt.Fprintf(os.Stderr, s, a...) |
| fmt.Fprintf(os.Stderr, "\n") |
| if (r.flags & PanicOnWarning) != 0 { |
| panic("unexpected warning") |
| } |
| } |
|
|
| func (r *CovDataReader) fatal(s string, a ...any) error { |
| if r.err != nil { |
| return nil |
| } |
| errstr := "error: " + fmt.Sprintf(s, a...) + "\n" |
| if (r.flags & PanicOnError) != 0 { |
| fmt.Fprintf(os.Stderr, "%s", errstr) |
| panic("fatal error") |
| } |
| r.err = fmt.Errorf("%s", errstr) |
| return r.err |
| } |
|
|
| |
| |
| func (r *CovDataReader) visitPod(p pods.Pod) error { |
| r.verb(1, "visiting pod: metafile %s with %d counter files", |
| p.MetaFile, len(p.CounterDataFiles)) |
| r.vis.BeginPod(p) |
|
|
| |
| f, err := os.Open(p.MetaFile) |
| if err != nil { |
| return r.fatal("unable to open meta-file %s", p.MetaFile) |
| } |
| defer f.Close() |
| br := bio.NewReader(f) |
| fi, err := f.Stat() |
| if err != nil { |
| return r.fatal("unable to stat metafile %s: %v", p.MetaFile, err) |
| } |
| fileView := br.SliceRO(uint64(fi.Size())) |
| br.MustSeek(0, io.SeekStart) |
|
|
| r.verb(1, "fileView for pod is length %d", len(fileView)) |
|
|
| var mfr *decodemeta.CoverageMetaFileReader |
| mfr, err = decodemeta.NewCoverageMetaFileReader(f, fileView) |
| if err != nil { |
| return r.fatal("decoding meta-file %s: %s", p.MetaFile, err) |
| } |
| r.vis.VisitMetaDataFile(p.MetaFile, mfr) |
|
|
| processCounterDataFile := func(cdf string, k int) error { |
| cf, err := os.Open(cdf) |
| if err != nil { |
| return r.fatal("opening counter data file %s: %s", cdf, err) |
| } |
| defer cf.Close() |
| var mr *MReader |
| mr, err = NewMreader(cf) |
| if err != nil { |
| return r.fatal("creating reader for counter data file %s: %s", cdf, err) |
| } |
| var cdr *decodecounter.CounterDataReader |
| cdr, err = decodecounter.NewCounterDataReader(cdf, mr) |
| if err != nil { |
| return r.fatal("reading counter data file %s: %s", cdf, err) |
| } |
| r.vis.BeginCounterDataFile(cdf, cdr, p.Origins[k]) |
| var data decodecounter.FuncPayload |
| for { |
| ok, err := cdr.NextFunc(&data) |
| if err != nil { |
| return r.fatal("reading counter data file %s: %v", cdf, err) |
| } |
| if !ok { |
| break |
| } |
| r.vis.VisitFuncCounterData(data) |
| } |
| r.vis.EndCounterDataFile(cdf, cdr, p.Origins[k]) |
| return nil |
| } |
|
|
| |
| for k, cdf := range p.CounterDataFiles { |
| if err := processCounterDataFile(cdf, k); err != nil { |
| return err |
| } |
| } |
| r.vis.EndCounters() |
|
|
| |
| |
| |
| np := uint32(mfr.NumPackages()) |
| payload := []byte{} |
| for pkIdx := uint32(0); pkIdx < np; pkIdx++ { |
| var pd *decodemeta.CoverageMetaDataDecoder |
| pd, payload, err = mfr.GetPackageDecoder(pkIdx, payload) |
| if err != nil { |
| return r.fatal("reading pkg %d from meta-file %s: %s", pkIdx, p.MetaFile, err) |
| } |
| r.processPackage(p.MetaFile, pd, pkIdx) |
| } |
| r.vis.EndPod(p) |
|
|
| return nil |
| } |
|
|
| func (r *CovDataReader) processPackage(mfname string, pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) error { |
| if r.matchpkg != nil { |
| if !r.matchpkg(pd.PackagePath()) { |
| return nil |
| } |
| } |
| r.vis.BeginPackage(pd, pkgIdx) |
| nf := pd.NumFuncs() |
| var fd coverage.FuncDesc |
| for fidx := uint32(0); fidx < nf; fidx++ { |
| if err := pd.ReadFunc(fidx, &fd); err != nil { |
| return r.fatal("reading meta-data file %s: %v", mfname, err) |
| } |
| r.vis.VisitFunc(pkgIdx, fidx, &fd) |
| } |
| r.vis.EndPackage(pd, pkgIdx) |
| return nil |
| } |
|
|