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(func() {
180 pprof.StopCPUProfile()
181 if err = f.Close(); err != nil {
182 fatal("error closing cpu profile: %v", err)
183 }
184 })
185 }
186 if *memprofileflag != "" {
187 if *memprofilerateflag != 0 {
188 runtime.MemProfileRate = *memprofilerateflag
189 }
190 f, err := os.Create(*memprofileflag)
191 if err != nil {
192 fatal("%v", err)
193 }
194 atExit(func() {
195 runtime.GC()
196 const writeLegacyFormat = 1
197 if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil {
198 fatal("%v", err)
199 }
200 if err = f.Close(); err != nil {
201 fatal("error closing memory profile: %v", err)
202 }
203 })
204 } else {
205
206 runtime.MemProfileRate = 0
207 }
208
209
210 op.Setup()
211
212
213 dbgtrace(1, "starting perform")
214
215 indirs := strings.Split(*indirsflag, ",")
216 vis := cov.CovDataVisitor(op)
217 var flags cov.CovDataReaderFlags
218 if *hflag {
219 flags |= cov.PanicOnError
220 }
221 if *hwflag {
222 flags |= cov.PanicOnWarning
223 }
224 reader := cov.MakeCovDataReader(vis, indirs, *verbflag, flags, matchpkg)
225 st := 0
226 if err := reader.Visit(); err != nil {
227 fmt.Fprintf(os.Stderr, "error: %v\n", err)
228 st = 1
229 }
230 dbgtrace(1, "leaving main")
231 Exit(st)
232 }
233
View as plain text