1
2
3
4
5 package main
6
7 import (
8 "cmd/internal/cov"
9 "cmd/internal/pkgpattern"
10 "flag"
11 "fmt"
12 "os"
13 "runtime"
14 "runtime/pprof"
15 "strings"
16 )
17
18 var verbflag = flag.Int("v", 0, "Verbose trace output level")
19 var hflag = flag.Bool("h", false, "Panic on fatal errors (for stack trace)")
20 var hwflag = flag.Bool("hw", false, "Panic on warnings (for stack trace)")
21 var indirsflag = flag.String("i", "", "Input dirs to examine (comma separated)")
22 var pkgpatflag = flag.String("pkg", "", "Restrict output to package(s) matching specified package pattern.")
23 var cpuprofileflag = flag.String("cpuprofile", "", "Write CPU profile to specified file")
24 var memprofileflag = flag.String("memprofile", "", "Write memory profile to specified file")
25 var memprofilerateflag = flag.Int("memprofilerate", 0, "Set memprofile sampling rate to value")
26
27 var matchpkg func(name string) bool
28
29 var atExitFuncs []func()
30
31 func atExit(f func()) {
32 atExitFuncs = append(atExitFuncs, f)
33 }
34
35 func Exit(code int) {
36 for i := len(atExitFuncs) - 1; i >= 0; i-- {
37 f := atExitFuncs[i]
38 atExitFuncs = atExitFuncs[:i]
39 f()
40 }
41 os.Exit(code)
42 }
43
44 func dbgtrace(vlevel int, s string, a ...interface{}) {
45 if *verbflag >= vlevel {
46 fmt.Printf(s, a...)
47 fmt.Printf("\n")
48 }
49 }
50
51 func warn(s string, a ...interface{}) {
52 fmt.Fprintf(os.Stderr, "warning: ")
53 fmt.Fprintf(os.Stderr, s, a...)
54 fmt.Fprintf(os.Stderr, "\n")
55 if *hwflag {
56 panic("unexpected warning")
57 }
58 }
59
60 func fatal(s string, a ...interface{}) {
61 fmt.Fprintf(os.Stderr, "error: ")
62 fmt.Fprintf(os.Stderr, s, a...)
63 fmt.Fprintf(os.Stderr, "\n")
64 if *hflag {
65 panic("fatal error")
66 }
67 Exit(1)
68 }
69
70 func usage(msg string) {
71 if len(msg) > 0 {
72 fmt.Fprintf(os.Stderr, "error: %s\n", msg)
73 }
74 fmt.Fprintf(os.Stderr, "usage: go tool covdata [command]\n")
75 fmt.Fprintf(os.Stderr, `
76 Commands are:
77
78 textfmt convert coverage data to textual format
79 percent output total percentage of statements covered
80 pkglist output list of package import paths
81 func output coverage profile information for each function
82 merge merge data files together
83 subtract subtract one set of data files from another set
84 intersect generate intersection of two sets of data files
85 debugdump dump data in human-readable format for debugging purposes
86 `)
87 fmt.Fprintf(os.Stderr, "\nFor help on a specific subcommand, try:\n")
88 fmt.Fprintf(os.Stderr, "\ngo tool covdata <cmd> -help\n")
89 Exit(2)
90 }
91
92 type covOperation interface {
93 cov.CovDataVisitor
94 Setup()
95 Usage(string)
96 }
97
98
99 const (
100 funcMode = "func"
101 mergeMode = "merge"
102 intersectMode = "intersect"
103 subtractMode = "subtract"
104 percentMode = "percent"
105 pkglistMode = "pkglist"
106 textfmtMode = "textfmt"
107 debugDumpMode = "debugdump"
108 )
109
110 func main() {
111
112 if len(os.Args) < 2 {
113 usage("missing command selector")
114 }
115
116
117 var op covOperation
118 cmd := os.Args[1]
119 switch cmd {
120 case mergeMode:
121 op = makeMergeOp()
122 case debugDumpMode:
123 op = makeDumpOp(debugDumpMode)
124 case textfmtMode:
125 op = makeDumpOp(textfmtMode)
126 case percentMode:
127 op = makeDumpOp(percentMode)
128 case funcMode:
129 op = makeDumpOp(funcMode)
130 case pkglistMode:
131 op = makeDumpOp(pkglistMode)
132 case subtractMode:
133 op = makeSubtractIntersectOp(subtractMode)
134 case intersectMode:
135 op = makeSubtractIntersectOp(intersectMode)
136 default:
137 usage(fmt.Sprintf("unknown command selector %q", cmd))
138 }
139
140
141 os.Args = append(os.Args[:1], os.Args[2:]...)
142 flag.Usage = func() {
143 op.Usage("")
144 }
145 flag.Parse()
146
147
148 dbgtrace(1, "starting mode-independent setup")
149 if flag.NArg() != 0 {
150 op.Usage("unknown extra arguments")
151 }
152 if *pkgpatflag != "" {
153 pats := strings.Split(*pkgpatflag, ",")
154 matchers := []func(name string) bool{}
155 for _, p := range pats {
156 if p == "" {
157 continue
158 }
159 f := pkgpattern.MatchSimplePattern(p)
160 matchers = append(matchers, f)
161 }
162 matchpkg = func(name string) bool {
163 for _, f := range matchers {
164 if f(name) {
165 return true
166 }
167 }
168 return false
169 }
170 }
171 if *cpuprofileflag != "" {
172 f, err := os.Create(*cpuprofileflag)
173 if err != nil {
174 fatal("%v", err)
175 }
176 if err := pprof.StartCPUProfile(f); err != nil {
177 fatal("%v", err)
178 }
179 atExit(pprof.StopCPUProfile)
180 }
181 if *memprofileflag != "" {
182 if *memprofilerateflag != 0 {
183 runtime.MemProfileRate = *memprofilerateflag
184 }
185 f, err := os.Create(*memprofileflag)
186 if err != nil {
187 fatal("%v", err)
188 }
189 atExit(func() {
190 runtime.GC()
191 const writeLegacyFormat = 1
192 if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil {
193 fatal("%v", err)
194 }
195 })
196 } else {
197
198 runtime.MemProfileRate = 0
199 }
200
201
202 op.Setup()
203
204
205 dbgtrace(1, "starting perform")
206
207 indirs := strings.Split(*indirsflag, ",")
208 vis := cov.CovDataVisitor(op)
209 var flags cov.CovDataReaderFlags
210 if *hflag {
211 flags |= cov.PanicOnError
212 }
213 if *hwflag {
214 flags |= cov.PanicOnWarning
215 }
216 reader := cov.MakeCovDataReader(vis, indirs, *verbflag, flags, matchpkg)
217 st := 0
218 if err := reader.Visit(); err != nil {
219 fmt.Fprintf(os.Stderr, "error: %v\n", err)
220 st = 1
221 }
222 dbgtrace(1, "leaving main")
223 Exit(st)
224 }
225
View as plain text