func instrumentAndTest() (rc int) { testFlags.Parse(os.Args[2:]) packageName := "." if testFlags.NArg() > 0 { packageName = testFlags.Arg(0) } tempDir, err := ioutil.TempDir("", "gocov") if err != nil { errorf("failed to create temporary GOROOT: %s\n", err) return 1 } if *testWorkFlag { fmt.Fprintf(os.Stderr, "WORK=%s\n", tempDir) } else { defer func() { err := os.RemoveAll(tempDir) if err != nil { fmt.Fprintf(os.Stderr, "warning: failed to delete temporary GOROOT (%s)\n", tempDir) } }() } goroot := runtime.GOROOT() for _, name := range [...]string{"src", "pkg", "bin", "lib", "include"} { dir := filepath.Join(goroot, name) err = symlinkHierarchy(dir, filepath.Join(tempDir, name)) if err != nil { errorf("failed to create $GOROOT/%s: %s\n", name, err) return 1 } } // Copy gocov into the temporary GOROOT, since otherwise it'll // be eclipsed by the instrumented packages root. if p, err := build.Import(gocovPackagePath, "", build.FindOnly); err == nil { err = symlinkHierarchy(p.Dir, filepath.Join(tempDir, "src", "pkg", gocovPackagePath)) if err != nil { errorf("failed to symlink gocov: %s\n", err) return 1 } } else { errorf("failed to locate gocov: %s\n", err) return 1 } var excluded []string if len(*testExcludeFlag) > 0 { excluded = strings.Split(*testExcludeFlag, ",") sort.Strings(excluded) } cwd, err := os.Getwd() if err != nil { errorf("failed to determine current working directory: %s\n", err) } in := &instrumenter{ gopath: tempDir, instrumented: make(map[string]*gocov.Package), excluded: excluded, processed: make(map[string]struct{}), workingdir: cwd} err, packageName = in.abspkgpath(packageName) if err != nil { errorf("failed to resolve package path(%s): %s\n", packageName, err) return 1 } err = in.instrumentPackage(packageName, true) if err != nil { errorf("failed to instrument package(%s): %s\n", packageName, err) return 1 } ninstrumented := 0 for _, pkg := range in.instrumented { if pkg != nil { ninstrumented++ } } if ninstrumented == 0 { errorf("error: no packages were instrumented\n") return 1 } // Run "go test". // TODO pass through test flags. outfilePath := filepath.Join(tempDir, "gocov.out") env := os.Environ() env = putenv(env, "GOCOVOUT", outfilePath) env = putenv(env, "GOROOT", tempDir) args := []string{"test"} if verbose { args = append(args, "-v") } if *testRunFlag != "" { args = append(args, "-run", *testRunFlag) } instrumentedPackageName := instrumentedPackagePath(packageName) args = append(args, instrumentedPackageName) cmd := exec.Command("go", args...) cmd.Env = env cmd.Stdout = os.Stderr cmd.Stderr = os.Stderr err = cmd.Run() if err != nil { errorf("go test failed: %s\n", err) rc = 1 } packages, err := parser.ParseTrace(outfilePath) if err != nil { errorf("failed to parse gocov output: %s\n", err) rc = 1 } else { data, err := marshalJson(packages) if err != nil { errorf("failed to format as JSON: %s\n", err) rc = 1 } else { fmt.Println(string(data)) } } return }
func instrumentAndTest() (rc int) { testFlags.Parse(os.Args[2:]) packagePaths, gotestArgs, err := packagesAndTestargs() if err != nil { errorf("failed to process package list: %s\n", err) return 1 } tempDir, err := ioutil.TempDir("", "gocov") if err != nil { errorf("failed to create temporary GOROOT: %s\n", err) return 1 } if *testWorkFlag { fmt.Fprintf(os.Stderr, "WORK=%s\n", tempDir) } else { defer func() { err := os.RemoveAll(tempDir) if err != nil { fmt.Fprintf(os.Stderr, "warning: failed to delete temporary GOROOT (%s)\n", tempDir) } }() } goroot := runtime.GOROOT() for _, name := range [...]string{"src", "pkg"} { dir := filepath.Join(goroot, name) err = symlinkHierarchy(dir, filepath.Join(tempDir, name)) if err != nil { errorf("failed to create $GOROOT/%s: %s\n", name, err) return 1 } } // Copy gocov into the temporary GOROOT, since otherwise it'll // be eclipsed by the instrumented packages root. Use the default // build context here since gocov doesn't use custom build tags. if p, err := build.Import(gocovPackagePath, "", build.FindOnly); err == nil { err = symlinkHierarchy(p.Dir, filepath.Join(tempDir, "src", "pkg", gocovPackagePath)) if err != nil { errorf("failed to symlink gocov: %s\n", err) return 1 } } else { errorf("failed to locate gocov: %s\n", err) return 1 } var excluded []string if len(*testExcludeFlag) > 0 { excluded = strings.Split(*testExcludeFlag, ",") sort.Strings(excluded) } cwd, err := os.Getwd() if err != nil { errorf("failed to determine current working directory: %s\n", err) } context := build.Default if *testTagsFlag != "" { context.BuildTags = strings.Fields(*testTagsFlag) } in := &instrumenter{ goroot: tempDir, context: context, instrumented: make(map[string]*gocov.Package), excluded: excluded, processed: make(map[string]bool), workingdir: cwd, } instrumentedPackagePaths := make([]string, len(packagePaths)) for i, packagePath := range packagePaths { var absPackagePath string absPackagePath, err = in.abspkgpath(packagePath) if err != nil { errorf("failed to resolve package path(%s): %s\n", packagePath, err) return 1 } packagePath = absPackagePath err = in.instrumentPackage(packagePath, true) if err != nil { errorf("failed to instrument package(%s): %s\n", packagePath, err) return 1 } instrumentedPackagePaths[i] = instrumentedPackagePath(packagePath) } ninstrumented := 0 for _, pkg := range in.instrumented { if pkg != nil { ninstrumented++ } } if ninstrumented == 0 { errorf("error: no packages were instrumented\n") return 1 } // Run "go test". const gocovOutPrefix = "gocov.out" env := os.Environ() env = putenv(env, "GOCOVOUT", filepath.Join(tempDir, gocovOutPrefix)) env = putenv(env, "GOROOT", tempDir) args := []string{"test"} if verbose { args = append(args, "-v") } if verboseX { args = append(args, "-x") } if *testTagsFlag != "" { args = append(args, "-tags", *testTagsFlag) } if *testRunFlag != "" { args = append(args, "-run", *testRunFlag) } if *testTimeoutFlag != "" { args = append(args, "-timeout", *testTimeoutFlag) } args = append(args, "-parallel", fmt.Sprint(*testParallelFlag)) args = append(args, instrumentedPackagePaths...) args = append(args, gotestArgs...) // First run with "-i" to avoid the warning // about out-of-date packages. testiargs := append([]string{args[0], "-i"}, args[1:]...) cmd := exec.Command("go", testiargs...) cmd.Env = env cmd.Stdout = os.Stderr cmd.Stderr = os.Stderr err = cmd.Run() if err != nil { errorf("go test -i failed: %s\n", err) return 1 } else { // Now run "go test" normally. cmd = exec.Command("go", args...) cmd.Env = env cmd.Stdout = os.Stderr cmd.Stderr = os.Stderr err = cmd.Run() if err != nil { errorf("go test failed: %s\n", err) return 1 } } tempDirFile, err := os.Open(tempDir) if err != nil { errorf("failed to open output directory: %s\n", err) return 1 } defer tempDirFile.Close() names, err := tempDirFile.Readdirnames(-1) if err != nil { errorf("failed to list output directory: %s\n", err) return 1 } var allpackages gocovutil.Packages for _, name := range names { if !strings.HasPrefix(name, gocovOutPrefix) { continue } outfilePath := filepath.Join(tempDir, name) packages, err := parser.ParseTrace(outfilePath) if err != nil { errorf("failed to parse gocov output: %s\n", err) return 1 } for _, p := range packages { allpackages.AddPackage(p) } } data, err := marshalJson(allpackages) if err != nil { errorf("failed to format as JSON: %s\n", err) return 1 } else { fmt.Println(string(data)) } return }
func instrumentAndTest() (rc int) { testFlags.Parse(os.Args[2:]) tempDir, err := ioutil.TempDir("", "gocov") if err != nil { errorf("failed to create temporary GOROOT: %s\n", err) return 1 } if *testWorkFlag { fmt.Fprintf(os.Stderr, "WORK=%s\n", tempDir) } else { defer func() { err := os.RemoveAll(tempDir) if err != nil { fmt.Fprintf(os.Stderr, "warning: failed to delete temporary GOROOT (%s)\n", tempDir) } }() } for _, name := range [...]string{"src", "pkg", "bin", "lib", "include"} { dir := filepath.Join(runtime.GOROOT(), name) err = symlinkHierarchy(dir, filepath.Join(tempDir, name)) if err != nil { errorf("failed to create $GOROOT/%s: %s\n", name, err) return 1 } } // Copy gocov into the temporary GOROOT, since otherwise it'll // be eclipsed by the instrumented packages root. if p, err := build.Import(gocovPackagePath, "", build.FindOnly); err == nil { err = symlinkHierarchy(p.Dir, filepath.Join(tempDir, "src", "pkg", gocovPackagePath)) if err != nil { errorf("failed to symlink gocov: %s\n", err) return 1 } } else { errorf("failed to locate gocov: %s\n", err) return 1 } var excluded []string if len(*testExcludeFlag) > 0 { excluded = strings.Split(*testExcludeFlag, ",") sort.Strings(excluded) } cwd, err := os.Getwd() if err != nil { errorf("failed to determine current working directory: %s\n", err) } in := &instrumenter{ gopath: tempDir, instrumented: make(map[string]*gocov.Package), excluded: excluded, processed: make(map[string]struct{}), workingdir: cwd, } for _, packageName := range importPaths(testFlags.Args()) { err, packageName = in.abspkgpath(packageName) if err != nil { errorf("failed to resolve package path(%s): %s\n", packageName, err) return 1 } if err := in.instrumentPackage(packageName, true); err != nil { warnf("warning: failed to instrument package(%s): %s\n", packageName, err) } } if in.ninstrumented() == 0 { errorf("error: no packages were instrumented\n") return 1 } // Run "go test". // TODO pass through test flags. outfile, err := ioutil.TempFile(tempDir, "gocov") if err != nil { errorf("could not create GOCOVOUT: %v", err) rc = 1 return } outfile.Close() outfilePath := outfile.Name() env := os.Environ() env = putenv(env, "GOCOVOUT", outfilePath) env = putenv(env, "GOROOT", tempDir) args := []string{"test", "-p", "1"} // disable parallel testing if verbose { args = append(args, "-v") } if *testRunFlag != "" { args = append(args, "-run", *testRunFlag) } args = append(args, testFlags.Args()...) cmd := exec.Command("go", args...) cmd.Env = env cmd.Stdout = os.Stderr cmd.Stderr = os.Stderr err = cmd.Run() if err != nil { errorf("go test failed: %s\n", err) rc = 1 } packages, err := parser.ParseTrace(outfilePath) if err != nil { errorf("failed to parse gocov output: %s\n", err) rc = 1 return } e := json.NewEncoder(os.Stdout) if err := e.Encode(struct{ Packages []*gocov.Package }{packages}); err != nil { errorf("failed to format as JSON: %s\n", err) rc = 1 } return }