// Collects all the source files from a single target func collectAllFiles(state *core.BuildState, target *core.BuildTarget, coveragePackages, allFiles map[string]bool, doneTargets map[*core.BuildTarget]bool, includeAllFiles bool) { doneTargets[target] = true if !includeAllFiles && !coveragePackages[target.Label.PackageName] { return } // Small hack here; explore these targets when we don't have any sources yet. Helps languages // like Java where we generate a wrapper target with a complete one immediately underneath. // TODO(pebers): do we still need this now we have Java sourcemaps? if !target.OutputIsComplete || len(allFiles) == 0 { for _, dep := range target.Dependencies() { if !doneTargets[dep] { collectAllFiles(state, dep, coveragePackages, allFiles, doneTargets, includeAllFiles) } } } if target.IsTest { return // Test sources don't count for coverage. } for _, path := range target.AllSourcePaths(state.Graph) { extension := filepath.Ext(path) for _, ext := range state.Config.Cover.FileExtension { if ext == extension { allFiles[path] = target.IsTest || target.TestOnly // Skip test source files from actual coverage display break } } } }
func makeJSONTarget(graph *core.BuildGraph, target *core.BuildTarget) JSONTarget { t := JSONTarget{} for in := range core.IterSources(graph, target) { t.Inputs = append(t.Inputs, in.Src) } for _, out := range target.Outputs() { t.Outputs = append(t.Outputs, path.Join(target.Label.PackageName, out)) } for _, src := range target.AllSourcePaths(graph) { t.Sources = append(t.Sources, src) } for _, dep := range target.Dependencies() { t.Deps = append(t.Deps, dep.Label.String()) } for data := range core.IterRuntimeFiles(graph, target, false) { t.Data = append(t.Data, data.Src) } t.Labels = target.Labels t.Requires = target.Requires rawHash := append(build.RuleHash(target, true, false), core.State.Hashes.Config...) t.Hash = base64.RawStdEncoding.EncodeToString(rawHash) t.Test = target.IsTest t.Binary = target.IsBinary t.TestOnly = target.TestOnly return t }
// Attempts to detect cycles in the build graph. Returns an empty slice if none is found, // otherwise returns a slice of labels describing the cycle. func findGraphCycle(graph *core.BuildGraph, target *core.BuildTarget) []*core.BuildTarget { index := func(haystack []*core.BuildTarget, needle *core.BuildTarget) int { for i, straw := range haystack { if straw == needle { return i } } return -1 } var detectCycle func(*core.BuildTarget, []*core.BuildTarget) []*core.BuildTarget detectCycle = func(target *core.BuildTarget, deps []*core.BuildTarget) []*core.BuildTarget { if i := index(deps, target); i != -1 { return deps[i:] } deps = append(deps, target) for _, dep := range target.Dependencies() { if cycle := detectCycle(dep, deps); len(cycle) > 0 { return cycle } } return nil } return detectCycle(target, nil) }
func printTarget(state *core.BuildState, target *core.BuildTarget, indent string, targets map[*core.BuildTarget]bool, unique bool) { if unique && targets[target] { return } targets[target] = true if target.ShouldInclude(state.Include, state.Exclude) { fmt.Printf("%s%s\n", indent, target.Label) } if !unique { indent = indent + " " } for _, dep := range target.Dependencies() { printTarget(state, dep, indent, targets, unique) } }
// Return true if the rule needs building, false if the existing outputs are OK. func needsBuilding(state *core.BuildState, target *core.BuildTarget, postBuild bool) bool { // Check the dependencies first, because they don't need any disk I/O. if target.NeedsTransitiveDependencies { if anyDependencyHasChanged(target) { return true // one of the transitive deps has changed, need to rebuild } } else { for _, dep := range target.Dependencies() { if dep.State() < core.Unchanged { log.Debug("Need to rebuild %s, %s has changed", target.Label, dep.Label) return true // dependency has just been rebuilt, do this too. } } } oldRuleHash, oldConfigHash, oldSourceHash := readRuleHashFile(ruleHashFileName(target), postBuild) if !bytes.Equal(oldConfigHash, state.Hashes.Config) { if len(oldConfigHash) == 0 { // Small nicety to make it a bit clearer what's going on. log.Debug("Need to build %s, outputs aren't there", target.Label) } else { log.Debug("Need to rebuild %s, config has changed (was %s, need %s)", target.Label, b64(oldConfigHash), b64(state.Hashes.Config)) } return true } newRuleHash := RuleHash(target, false, postBuild) if !bytes.Equal(oldRuleHash, newRuleHash) { log.Debug("Need to rebuild %s, rule has changed (was %s, need %s)", target.Label, b64(oldRuleHash), b64(newRuleHash)) return true } newSourceHash, err := sourceHash(state.Graph, target) if err != nil || !bytes.Equal(oldSourceHash, newSourceHash) { log.Debug("Need to rebuild %s, sources have changed (was %s, need %s)", target.Label, b64(oldSourceHash), b64(newSourceHash)) return true } // Check the outputs of this rule exist. This would only happen if the user had // removed them but it's incredibly aggravating if you remove an output and the // rule won't rebuild itself. for _, output := range target.Outputs() { realOutput := path.Join(target.OutDir(), output) if !core.PathExists(realOutput) { log.Debug("Output %s doesn't exist for rule %s; will rebuild.", realOutput, target.Label) return true } } // Maybe we've forced a rebuild. Do this last; might be interesting to see if it needed building anyway. return state.ForceRebuild && (state.IsOriginalTarget(target.Label) || state.IsOriginalTarget(target.Label.Parent())) }