func printBuildResults(state *core.BuildState, duration float64) { // Count incrementality. totalBuilt := 0 totalReused := 0 for _, target := range state.Graph.AllTargets() { if target.State() == core.Built { totalBuilt++ } else if target.State() == core.Reused { totalReused++ } } incrementality := 100.0 * float64(totalReused) / float64(totalBuilt+totalReused) if totalBuilt+totalReused == 0 { incrementality = 100 // avoid NaN } // Print this stuff so we always see it. printf("Build finished; total time %0.2fs, incrementality %.1f%%. Outputs:\n", duration, incrementality) for _, label := range state.ExpandOriginalTargets() { target := state.Graph.TargetOrDie(label) fmt.Printf("%s:\n", label) for _, result := range buildResult(target) { fmt.Printf(" %s\n", result) } } }
func MonitorState(state *core.BuildState, numThreads int, plainOutput, keepGoing, shouldBuild, shouldTest, shouldRun bool, traceFile string) bool { failedTargetMap := map[core.BuildLabel]error{} buildingTargets := make([]buildingTarget, numThreads, numThreads) displayDone := make(chan interface{}) stop := make(chan interface{}) if !plainOutput { go display(state, &buildingTargets, stop, displayDone) } aggregatedResults := core.TestResults{} failedTargets := []core.BuildLabel{} failedNonTests := []core.BuildLabel{} for result := range state.Results { processResult(state, result, buildingTargets, &aggregatedResults, plainOutput, keepGoing, &failedTargets, &failedNonTests, failedTargetMap, traceFile != "") } if !plainOutput { stop <- struct{}{} <-displayDone } if traceFile != "" { writeTrace(traceFile) } duration := time.Since(startTime).Seconds() if len(failedNonTests) > 0 { // Something failed in the build step. if state.Verbosity > 0 { printFailedBuildResults(failedNonTests, failedTargetMap, duration) } // Die immediately and unsuccessfully, this avoids awkward interactions with // --failing_tests_ok later on. os.Exit(-1) } // Check all the targets we wanted to build actually have been built. for _, label := range state.ExpandOriginalTargets() { if target := state.Graph.Target(label); target == nil { log.Fatalf("Target %s doesn't exist in build graph", label) } else if (state.NeedHashesOnly || state.PrepareOnly) && target.State() == core.Stopped { // Do nothing, we will output about this shortly. } else if shouldBuild && target != nil && target.State() < core.Built && len(failedTargetMap) == 0 { cycle := graphCycleMessage(state.Graph, target) log.Fatalf("Target %s hasn't built but we have no pending tasks left.\n%s", label, cycle) } } if state.Verbosity > 0 && shouldBuild { if shouldTest { // Got to the test phase, report their results. printTestResults(state, aggregatedResults, failedTargets, duration) } else if state.NeedHashesOnly { printHashes(state, duration) } else if state.PrepareOnly { printTempDirs(state, duration) } else if !shouldRun { // Must be plz build or similar, report build outputs. printBuildResults(state, duration) } } return len(failedTargetMap) == 0 }
func printTempDirs(state *core.BuildState, duration float64) { fmt.Printf("Temp directories prepared, total time %0.2fs:\n", duration) for _, label := range state.ExpandOriginalTargets() { target := state.Graph.TargetOrDie(label) cmd := build.ReplaceSequences(target, target.GetCommand()) env := core.BuildEnvironment(state, target, false) fmt.Printf(" %s: %s\n", label, target.TmpDir()) fmt.Printf(" Command: %s\n", cmd) fmt.Printf(" Expanded: %s\n", os.Expand(cmd, core.ReplaceEnvironment(env))) } }
func printHashes(state *core.BuildState, duration float64) { fmt.Printf("Hashes calculated, total time %0.2fs:\n", duration) for _, label := range state.ExpandOriginalTargets() { hash, err := build.OutputHash(state.Graph.TargetOrDie(label)) if err != nil { fmt.Printf(" %s: cannot calculate: %s\n", label, err) } else { fmt.Printf(" %s: %s\n", label, hex.EncodeToString(hash)) } } }
// Adds empty coverage entries for any files covered by the original query that we // haven't discovered through tests to the overall report. // The coverage reports only contain information about files that were covered during // tests, so it's important that we identify anything with zero coverage here. // This is made trickier by attempting to reconcile coverage targets from languages like // Java that don't preserve the original file structure, which requires a slightly fuzzy match. func AddOriginalTargetsToCoverage(state *core.BuildState, includeAllFiles bool) { // First we collect all the source files from all relevant targets allFiles := map[string]bool{} doneTargets := map[*core.BuildTarget]bool{} // Track the set of packages the user ran tests from; we only show coverage metrics from them. coveragePackages := map[string]bool{} for _, label := range state.OriginalTargets { coveragePackages[label.PackageName] = true } for _, label := range state.ExpandOriginalTargets() { collectAllFiles(state, state.Graph.TargetOrDie(label), coveragePackages, allFiles, doneTargets, includeAllFiles) } // Now merge the recorded coverage so far into them recordedCoverage := state.Coverage state.Coverage = core.TestCoverage{Tests: recordedCoverage.Tests, Files: map[string][]core.LineCoverage{}} mergeCoverage(state, recordedCoverage, coveragePackages, allFiles, includeAllFiles) }