| | |
| | |
| | |
| |
|
| | package main |
| |
|
| | import ( |
| | "cmd/internal/cov" |
| | "cmd/internal/pkgpattern" |
| | "cmd/internal/telemetry/counter" |
| | "flag" |
| | "fmt" |
| | "os" |
| | "runtime" |
| | "runtime/pprof" |
| | "strings" |
| | ) |
| |
|
| | var verbflag = flag.Int("v", 0, "Verbose trace output level") |
| | var hflag = flag.Bool("h", false, "Panic on fatal errors (for stack trace)") |
| | var hwflag = flag.Bool("hw", false, "Panic on warnings (for stack trace)") |
| | var indirsflag = flag.String("i", "", "Input dirs to examine (comma separated)") |
| | var pkgpatflag = flag.String("pkg", "", "Restrict output to package(s) matching specified package pattern.") |
| | var cpuprofileflag = flag.String("cpuprofile", "", "Write CPU profile to specified file") |
| | var memprofileflag = flag.String("memprofile", "", "Write memory profile to specified file") |
| | var memprofilerateflag = flag.Int("memprofilerate", 0, "Set memprofile sampling rate to value") |
| |
|
| | var matchpkg func(name string) bool |
| |
|
| | var atExitFuncs []func() |
| |
|
| | func atExit(f func()) { |
| | atExitFuncs = append(atExitFuncs, f) |
| | } |
| |
|
| | func Exit(code int) { |
| | for i := len(atExitFuncs) - 1; i >= 0; i-- { |
| | f := atExitFuncs[i] |
| | atExitFuncs = atExitFuncs[:i] |
| | f() |
| | } |
| | os.Exit(code) |
| | } |
| |
|
| | func dbgtrace(vlevel int, s string, a ...any) { |
| | if *verbflag >= vlevel { |
| | fmt.Printf(s, a...) |
| | fmt.Printf("\n") |
| | } |
| | } |
| |
|
| | func warn(s string, a ...any) { |
| | fmt.Fprintf(os.Stderr, "warning: ") |
| | fmt.Fprintf(os.Stderr, s, a...) |
| | fmt.Fprintf(os.Stderr, "\n") |
| | if *hwflag { |
| | panic("unexpected warning") |
| | } |
| | } |
| |
|
| | func fatal(s string, a ...any) { |
| | fmt.Fprintf(os.Stderr, "error: ") |
| | fmt.Fprintf(os.Stderr, s, a...) |
| | fmt.Fprintf(os.Stderr, "\n") |
| | if *hflag { |
| | panic("fatal error") |
| | } |
| | Exit(1) |
| | } |
| |
|
| | func usage(msg string) { |
| | if len(msg) > 0 { |
| | fmt.Fprintf(os.Stderr, "error: %s\n", msg) |
| | } |
| | fmt.Fprintf(os.Stderr, "usage: go tool covdata [command]\n") |
| | fmt.Fprintf(os.Stderr, ` |
| | Commands are: |
| | |
| | textfmt convert coverage data to textual format |
| | percent output total percentage of statements covered |
| | pkglist output list of package import paths |
| | func output coverage profile information for each function |
| | merge merge data files together |
| | subtract subtract one set of data files from another set |
| | intersect generate intersection of two sets of data files |
| | debugdump dump data in human-readable format for debugging purposes |
| | `) |
| | fmt.Fprintf(os.Stderr, "\nFor help on a specific subcommand, try:\n") |
| | fmt.Fprintf(os.Stderr, "\ngo tool covdata <cmd> -help\n") |
| | Exit(2) |
| | } |
| |
|
| | type covOperation interface { |
| | cov.CovDataVisitor |
| | Setup() |
| | Usage(string) |
| | } |
| |
|
| | |
| | const ( |
| | funcMode = "func" |
| | mergeMode = "merge" |
| | intersectMode = "intersect" |
| | subtractMode = "subtract" |
| | percentMode = "percent" |
| | pkglistMode = "pkglist" |
| | textfmtMode = "textfmt" |
| | debugDumpMode = "debugdump" |
| | ) |
| |
|
| | func main() { |
| | counter.Open() |
| |
|
| | |
| | if len(os.Args) < 2 { |
| | usage("missing command selector") |
| | } |
| |
|
| | |
| | var op covOperation |
| | cmd := os.Args[1] |
| | switch cmd { |
| | case mergeMode: |
| | op = makeMergeOp() |
| | case debugDumpMode: |
| | op = makeDumpOp(debugDumpMode) |
| | case textfmtMode: |
| | op = makeDumpOp(textfmtMode) |
| | case percentMode: |
| | op = makeDumpOp(percentMode) |
| | case funcMode: |
| | op = makeDumpOp(funcMode) |
| | case pkglistMode: |
| | op = makeDumpOp(pkglistMode) |
| | case subtractMode: |
| | op = makeSubtractIntersectOp(subtractMode) |
| | case intersectMode: |
| | op = makeSubtractIntersectOp(intersectMode) |
| | default: |
| | usage(fmt.Sprintf("unknown command selector %q", cmd)) |
| | } |
| |
|
| | |
| | os.Args = append(os.Args[:1], os.Args[2:]...) |
| | flag.Usage = func() { |
| | op.Usage("") |
| | } |
| | flag.Parse() |
| | counter.Inc("covdata/invocations") |
| | counter.CountFlags("covdata/flag:", *flag.CommandLine) |
| |
|
| | |
| | dbgtrace(1, "starting mode-independent setup") |
| | if flag.NArg() != 0 { |
| | op.Usage("unknown extra arguments") |
| | } |
| | if *pkgpatflag != "" { |
| | pats := strings.Split(*pkgpatflag, ",") |
| | matchers := []func(name string) bool{} |
| | for _, p := range pats { |
| | if p == "" { |
| | continue |
| | } |
| | f := pkgpattern.MatchSimplePattern(p) |
| | matchers = append(matchers, f) |
| | } |
| | matchpkg = func(name string) bool { |
| | for _, f := range matchers { |
| | if f(name) { |
| | return true |
| | } |
| | } |
| | return false |
| | } |
| | } |
| | if *cpuprofileflag != "" { |
| | f, err := os.Create(*cpuprofileflag) |
| | if err != nil { |
| | fatal("%v", err) |
| | } |
| | if err := pprof.StartCPUProfile(f); err != nil { |
| | fatal("%v", err) |
| | } |
| | atExit(func() { |
| | pprof.StopCPUProfile() |
| | if err = f.Close(); err != nil { |
| | fatal("error closing cpu profile: %v", err) |
| | } |
| | }) |
| | } |
| | if *memprofileflag != "" { |
| | if *memprofilerateflag != 0 { |
| | runtime.MemProfileRate = *memprofilerateflag |
| | } |
| | f, err := os.Create(*memprofileflag) |
| | if err != nil { |
| | fatal("%v", err) |
| | } |
| | atExit(func() { |
| | runtime.GC() |
| | const writeLegacyFormat = 1 |
| | if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil { |
| | fatal("%v", err) |
| | } |
| | if err = f.Close(); err != nil { |
| | fatal("error closing memory profile: %v", err) |
| | } |
| | }) |
| | } else { |
| | |
| | runtime.MemProfileRate = 0 |
| | } |
| |
|
| | |
| | op.Setup() |
| |
|
| | |
| | dbgtrace(1, "starting perform") |
| |
|
| | indirs := strings.Split(*indirsflag, ",") |
| | vis := cov.CovDataVisitor(op) |
| | var flags cov.CovDataReaderFlags |
| | if *hflag { |
| | flags |= cov.PanicOnError |
| | } |
| | if *hwflag { |
| | flags |= cov.PanicOnWarning |
| | } |
| | reader := cov.MakeCovDataReader(vis, indirs, *verbflag, flags, matchpkg) |
| | st := 0 |
| | if err := reader.Visit(); err != nil { |
| | fmt.Fprintf(os.Stderr, "error: %v\n", err) |
| | st = 1 |
| | } |
| | dbgtrace(1, "leaving main") |
| | Exit(st) |
| | } |
| |
|