func Build(tid int, state *core.BuildState, label core.BuildLabel) { start := time.Now() target := state.Graph.TargetOrDie(label) target.SetState(core.Building) if err := buildTarget(tid, state, target); err != nil { if err == stopTarget { target.SetState(core.Stopped) state.LogBuildResult(tid, target.Label, core.TargetBuildStopped, "Build stopped") return } state.LogBuildError(tid, label, core.TargetBuildFailed, err, "Build failed: %s", err) if err := RemoveOutputs(target); err != nil { log.Errorf("Failed to remove outputs for %s: %s", target.Label, err) } target.SetState(core.Failed) return } metrics.Record(target, time.Since(start)) // Add any of the reverse deps that are now fully built to the queue. for _, reverseDep := range state.Graph.ReverseDependencies(target) { if reverseDep.State() == core.Active && state.Graph.AllDepsBuilt(reverseDep) && reverseDep.SyncUpdateState(core.Active, core.Pending) { state.AddPendingBuild(reverseDep.Label, false) } } if target.IsTest && state.NeedTests { state.AddPendingTest(target.Label) } parse.UndeferAnyParses(state, target) }
func addTarget(state *core.BuildState, i int) *core.BuildTarget { // Create and add a new target, with a parent and a dependency. target := core.NewBuildTarget(label(i)) target.Command = "__FILEGROUP__" // Will mean it doesn't have to shell out to anything. target.SetState(core.Active) state.Graph.AddTarget(target) if i <= size { if i > 10 { target.Flakiness = i // Stash this here, will be useful later. target.PostBuildFunction = reflect.ValueOf(&postBuildFunc).Pointer() } if i < size/10 { for j := 0; j < 10; j++ { dep := label(i*10 + j) log.Info("Adding dependency %s -> %s", target.Label, dep) target.AddDependency(dep) state.Graph.AddDependency(target.Label, dep) } } else { // These are buildable now state.AddPendingBuild(target.Label, false) } } state.AddActiveTarget() return target }
// Adds a single target to the build queue. func addDep(state *core.BuildState, label, dependor core.BuildLabel, rescan, forceBuild bool) { // Stop at any package that's not loaded yet if state.Graph.Package(label.PackageName) == nil { state.AddPendingParse(label, dependor, false) return } target := state.Graph.Target(label) if target == nil { log.Fatalf("Target %s (referenced by %s) doesn't exist\n", label, dependor) } if target.State() >= core.Active && !rescan && !forceBuild { return // Target is already tagged to be built and likely on the queue. } // Only do this bit if we actually need to build the target if !target.SyncUpdateState(core.Inactive, core.Semiactive) && !rescan && !forceBuild { return } if state.NeedBuild || forceBuild { if target.SyncUpdateState(core.Semiactive, core.Active) { state.AddActiveTarget() if target.IsTest && state.NeedTests { state.AddActiveTarget() // Tests count twice if we're gonna run them. } } } // If this target has no deps, add it to the queue now, otherwise handle its deps. // Only add if we need to build targets (not if we're just parsing) but we might need it to parse... if target.State() == core.Active && state.Graph.AllDepsBuilt(target) { if target.SyncUpdateState(core.Active, core.Pending) { state.AddPendingBuild(label, dependor.IsAllTargets()) } if !rescan { return } } for _, dep := range target.DeclaredDependencies() { // Check the require/provide stuff; we may need to add a different target. if len(target.Requires) > 0 { if depTarget := state.Graph.Target(dep); depTarget != nil && len(depTarget.Provides) > 0 { for _, provided := range depTarget.ProvideFor(target) { addDep(state, provided, label, false, forceBuild) } continue } } addDep(state, dep, label, false, forceBuild) } }