// htmlOutput reads the profile data from profile and generates an HTML // coverage report, writing it to outfile. If outfile is empty, // it writes the report to a temporary file and opens it in a web browser. func htmlOutput(profile, outfile string) error { profiles, err := ParseProfiles(profile) if err != nil { return err } var d templateData for _, profile := range profiles { fn := profile.FileName if profile.Mode == "set" { d.Set = true } file, err := findFile(fn) if err != nil { return err } src, err := ioutil.ReadFile(file) if err != nil { return fmt.Errorf("can't read %q: %v", fn, err) } var buf bytes.Buffer err = htmlGen(&buf, src, profile.Boundaries(src)) if err != nil { return err } d.Files = append(d.Files, &templateFile{ Name: fn, Body: template.HTML(buf.String()), Coverage: percentCovered(profile), }) } var out *os.File if outfile == "" { var dir string dir, err = ioutil.TempDir("", "cover") if err != nil { return err } out, err = os.Create(filepath.Join(dir, "coverage.html")) } else { out, err = os.Create(outfile) } err = htmlTemplate.Execute(out, d) if err == nil { err = out.Close() } if err != nil { return err } if outfile == "" { if !browser.Open("file://" + out.Name()) { fmt.Fprintf(os.Stderr, "HTML output written to %s\n", out.Name()) } } return nil }
func openBrowser(url string) bool { return browser.Open(url) }
func main() { flag.Usage = func() { fmt.Fprintln(os.Stderr, usageMessage) os.Exit(2) } flag.Parse() // Go 1.7 traces embed symbol info and does not require the binary. // But we optionally accept binary as first arg for Go 1.5 traces. switch flag.NArg() { case 1: traceFile = flag.Arg(0) case 2: programBinary = flag.Arg(0) traceFile = flag.Arg(1) default: flag.Usage() } var pprofFunc func(io.Writer) error switch *pprofFlag { case "net": pprofFunc = pprofIO case "sync": pprofFunc = pprofBlock case "syscall": pprofFunc = pprofSyscall case "sched": pprofFunc = pprofSched } if pprofFunc != nil { if err := pprofFunc(os.Stdout); err != nil { dief("failed to generate pprof: %v\n", err) } os.Exit(0) } if *pprofFlag != "" { dief("unknown pprof type %s\n", *pprofFlag) } ln, err := net.Listen("tcp", *httpFlag) if err != nil { dief("failed to create server socket: %v\n", err) } log.Printf("Parsing trace...") events, err := parseEvents() if err != nil { dief("%v\n", err) } log.Printf("Serializing trace...") params := &traceParams{ events: events, endTime: int64(1<<63 - 1), } data, err := generateTrace(params) if err != nil { dief("%v\n", err) } log.Printf("Splitting trace...") ranges = splitTrace(data) log.Printf("Opening browser") if !browser.Open("http://" + ln.Addr().String()) { fmt.Fprintf(os.Stderr, "Trace viewer is listening on http://%s\n", ln.Addr().String()) } // Start http server. http.HandleFunc("/", httpMain) err = http.Serve(ln, nil) dief("failed to start http server: %v\n", err) }