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