1// Copyright 2022 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package main 6 7// This file contains functions and apis to support the "merge" 8// subcommand of "go tool covdata". 9 10import ( 11 "flag" 12 "fmt" 13 "internal/coverage" 14 "internal/coverage/cmerge" 15 "internal/coverage/decodecounter" 16 "internal/coverage/decodemeta" 17 "internal/coverage/pods" 18 "os" 19) 20 21var outdirflag *string 22var pcombineflag *bool 23 24func makeMergeOp() covOperation { 25 outdirflag = flag.String("o", "", "Output directory to write") 26 pcombineflag = flag.Bool("pcombine", false, "Combine profiles derived from distinct program executables") 27 m := &mstate{ 28 mm: newMetaMerge(), 29 } 30 return m 31} 32 33// mstate encapsulates state and provides methods for implementing the 34// merge operation. This type implements the CovDataVisitor interface, 35// and is designed to be used in concert with the CovDataReader 36// utility, which abstracts away most of the grubby details of reading 37// coverage data files. Most of the heavy lifting for merging is done 38// using apis from 'metaMerge' (this is mainly a wrapper around that 39// functionality). 40type mstate struct { 41 mm *metaMerge 42} 43 44func (m *mstate) Usage(msg string) { 45 if len(msg) > 0 { 46 fmt.Fprintf(os.Stderr, "error: %s\n", msg) 47 } 48 fmt.Fprintf(os.Stderr, "usage: go tool covdata merge -i=<directories> -o=<dir>\n\n") 49 flag.PrintDefaults() 50 fmt.Fprintf(os.Stderr, "\nExamples:\n\n") 51 fmt.Fprintf(os.Stderr, " go tool covdata merge -i=dir1,dir2,dir3 -o=outdir\n\n") 52 fmt.Fprintf(os.Stderr, " \tmerges all files in dir1/dir2/dir3\n") 53 fmt.Fprintf(os.Stderr, " \tinto output dir outdir\n") 54 Exit(2) 55} 56 57func (m *mstate) Setup() { 58 if *indirsflag == "" { 59 m.Usage("select input directories with '-i' option") 60 } 61 if *outdirflag == "" { 62 m.Usage("select output directory with '-o' option") 63 } 64 m.mm.SetModeMergePolicy(cmerge.ModeMergeRelaxed) 65} 66 67func (m *mstate) BeginPod(p pods.Pod) { 68 m.mm.beginPod() 69} 70 71func (m *mstate) EndPod(p pods.Pod) { 72 m.mm.endPod(*pcombineflag) 73} 74 75func (m *mstate) BeginCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) { 76 dbgtrace(2, "visit counter data file %s dirIdx %d", cdf, dirIdx) 77 m.mm.beginCounterDataFile(cdr) 78} 79 80func (m *mstate) EndCounterDataFile(cdf string, cdr *decodecounter.CounterDataReader, dirIdx int) { 81} 82 83func (m *mstate) VisitFuncCounterData(data decodecounter.FuncPayload) { 84 m.mm.visitFuncCounterData(data) 85} 86 87func (m *mstate) EndCounters() { 88} 89 90func (m *mstate) VisitMetaDataFile(mdf string, mfr *decodemeta.CoverageMetaFileReader) { 91 m.mm.visitMetaDataFile(mdf, mfr) 92} 93 94func (m *mstate) BeginPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) { 95 dbgtrace(3, "VisitPackage(pk=%d path=%s)", pkgIdx, pd.PackagePath()) 96 m.mm.visitPackage(pd, pkgIdx, *pcombineflag) 97} 98 99func (m *mstate) EndPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32) { 100} 101 102func (m *mstate) VisitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc) { 103 m.mm.visitFunc(pkgIdx, fnIdx, fd, mergeMode, *pcombineflag) 104} 105 106func (m *mstate) Finish() { 107 if *pcombineflag { 108 finalHash := m.mm.emitMeta(*outdirflag, true) 109 m.mm.emitCounters(*outdirflag, finalHash) 110 } 111} 112