// panic if node is in an impossible state for starting its visit func checkInitialState(node dag.Node) { if node.State() != dag.UNKNOWN { // we just skipped SOURCE nodes, the other states are only set // while visiting a node, and we should only visit each node // once panic(fmt.Sprintf( "visiting node %v, state = %s (should be UNKNOWN)", node, node.State())) } }
// Build the specified node (caller has determined that it should be // built and can be built). On failure, report the error (e.g. to the // console, a GUI window, ...) and return false. On success, return // true. func (self *BuildState) buildNode(node dag.Node, builderr *BuildError) bool { rule := node.BuildRule() log.Verbose("building node %s, action=%s\n", node, rule.ActionString()) node.SetState(dag.BUILDING) builderr.attempts++ targets, errs := rule.Execute() if len(errs) > 0 { // Normal, everyday build failure: report the precise problem // immediately, and accumulate summary info in the caller. for _, tnode := range targets { tnode.SetState(dag.FAILED) } self.reportFailure(errs) builderr.addFailure(node) return false } for _, tnode := range targets { tnode.SetState(dag.BUILT) } return true }
func (self *BuildState) parentChanged( parent dag.Node, pstate dag.NodeState, oldsig []byte) ( bool, error) { var cursig []byte var err error if !(pstate == dag.SOURCE || pstate == dag.BUILT || self.checkAll()) { // parent is an intermediate target that has not been built in // the current run. We don't want the expense of calling // Signature() for target nodes, because people don't normally // modify targets behind their build tool's back. But it might // have been modified by a previous build, in which case we'll // use the signature previously recorded for parent *as a // target*. This can still be fooled by modifying intermediate // targets behind Fubsy's back, but that's what --check-all is // for. precord, err := self.db.LookupNode(parent.Name()) if err != nil { return false, err } if precord != nil { cursig = precord.TargetSignature() } } if cursig == nil { cursig, err = parent.Signature() if err != nil { // This should not happen: parent should exist and be readable, // since we've already visited it earlier in the build and we // avoid looking at failed/tainted parents. return false, err } } changed := parent.Changed(cursig, oldsig) //log.Verbose("parent %s: oldsig=%v, cursig=%v, changed=%v", // parent, oldsig, cursig, changed) return changed, nil }
func (self *BuildState) recordNode(node dag.Node) error { log.Debug(log.BUILD, "recording successful build of %s %s", node.Typename(), node) sig, err := node.Signature() log.Debug(log.BUILD, "sig=%v, err=%v", sig, err) if err != nil { return fmt.Errorf("could not compute signature of target %s: %s", node, err) } record := db.NewBuildRecord() record.SetTargetSignature(sig) for _, parent := range self.graph.ParentNodes(node) { sig, err = parent.Signature() if err != nil { return err } record.AddParent(parent.Name(), sig) } err = self.db.WriteNode(node.Name(), record) if err != nil { return err } return nil }
// Inspect node and its parents to see if we need to build it. Return // build=true if we should build it, tainted=true if we should skip // building this node due to upstream failure. Return non-nil err if // there were unexpected node errors (error checking existence or // change status). func (self *BuildState) considerNode(node dag.Node) ( build bool, tainted bool, err error) { var exists, changed bool exists, err = node.Exists() // obvious rebuild (unless tainted) if err != nil { return } missing := !exists var record *db.BuildRecord if !missing { // skip DB lookup for missing nodes: the only thing that will // stop us from rebuilding them is a failed parent, and that // check comes later record, err = self.db.LookupNode(node.Name()) if err != nil { return } if record != nil { log.Debug(log.BUILD, "old parents of %s:", node) log.DebugDump(log.BUILD, record) } } build = missing parents := self.graph.ParentNodes(node) // Check if any of node's former parents have been removed. if !build && record != nil { build = parentsRemoved(parents, record) } for _, parent := range parents { pstate := parent.State() if pstate == dag.FAILED || pstate == dag.TAINTED { build = false tainted = true return // no further inspection required } var oldsig []byte if record != nil { oldsig = record.SourceSignature(parent.Name()) } if oldsig == nil { // New parent for this node: rebuild unless another // parent is failed/tainted. build = true } if build { continue } changed, err = self.parentChanged(parent, pstate, oldsig) if err != nil { return } if changed { // Do NOT return here: we need to continue inspecting // parents to make sure they don't taint this node with // upstream failure. build = true } } return }