| // Copyright 2014 Google Inc. All rights reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| package blueprint | |
| import "sync" | |
| // A liveTracker tracks the values of live variables, rules, and pools. An | |
| // entity is made "live" when it is referenced directly or indirectly by a build | |
| // definition. When an entity is made live its value is computed based on the | |
| // configuration. | |
| type liveTracker struct { | |
| sync.Mutex | |
| config interface{} // Used to evaluate variable, rule, and pool values. | |
| ctx *Context // Used to evaluate globs | |
| variables map[Variable]ninjaString | |
| pools map[Pool]*poolDef | |
| rules map[Rule]*ruleDef | |
| } | |
| func newLiveTracker(ctx *Context, config interface{}) *liveTracker { | |
| return &liveTracker{ | |
| ctx: ctx, | |
| config: config, | |
| variables: make(map[Variable]ninjaString), | |
| pools: make(map[Pool]*poolDef), | |
| rules: make(map[Rule]*ruleDef), | |
| } | |
| } | |
| func (l *liveTracker) AddBuildDefDeps(def *buildDef) error { | |
| l.Lock() | |
| defer l.Unlock() | |
| ruleDef, err := l.addRule(def.Rule) | |
| if err != nil { | |
| return err | |
| } | |
| def.RuleDef = ruleDef | |
| err = l.addNinjaStringListDeps(def.Outputs) | |
| if err != nil { | |
| return err | |
| } | |
| err = l.addNinjaStringListDeps(def.Inputs) | |
| if err != nil { | |
| return err | |
| } | |
| err = l.addNinjaStringListDeps(def.Implicits) | |
| if err != nil { | |
| return err | |
| } | |
| err = l.addNinjaStringListDeps(def.OrderOnly) | |
| if err != nil { | |
| return err | |
| } | |
| err = l.addNinjaStringListDeps(def.Validations) | |
| if err != nil { | |
| return err | |
| } | |
| for _, value := range def.Variables { | |
| err = l.addNinjaStringDeps(value) | |
| if err != nil { | |
| return err | |
| } | |
| } | |
| for _, value := range def.Args { | |
| err = l.addNinjaStringDeps(value) | |
| if err != nil { | |
| return err | |
| } | |
| } | |
| return nil | |
| } | |
| func (l *liveTracker) addRule(r Rule) (def *ruleDef, err error) { | |
| def, ok := l.rules[r] | |
| if !ok { | |
| def, err = r.def(l.config) | |
| if err == errRuleIsBuiltin { | |
| // No need to do anything for built-in rules. | |
| return nil, nil | |
| } | |
| if err != nil { | |
| return nil, err | |
| } | |
| if def.Pool != nil { | |
| err = l.addPool(def.Pool) | |
| if err != nil { | |
| return nil, err | |
| } | |
| } | |
| err = l.addNinjaStringListDeps(def.CommandDeps) | |
| if err != nil { | |
| return nil, err | |
| } | |
| err = l.addNinjaStringListDeps(def.CommandOrderOnly) | |
| if err != nil { | |
| return nil, err | |
| } | |
| for _, value := range def.Variables { | |
| err = l.addNinjaStringDeps(value) | |
| if err != nil { | |
| return nil, err | |
| } | |
| } | |
| l.rules[r] = def | |
| } | |
| return | |
| } | |
| func (l *liveTracker) addPool(p Pool) error { | |
| _, ok := l.pools[p] | |
| if !ok { | |
| def, err := p.def(l.config) | |
| if err == errPoolIsBuiltin { | |
| // No need to do anything for built-in rules. | |
| return nil | |
| } | |
| if err != nil { | |
| return err | |
| } | |
| l.pools[p] = def | |
| } | |
| return nil | |
| } | |
| func (l *liveTracker) addVariable(v Variable) error { | |
| _, ok := l.variables[v] | |
| if !ok { | |
| ctx := &variableFuncContext{l.ctx} | |
| value, err := v.value(ctx, l.config) | |
| if err == errVariableIsArg { | |
| // This variable is a placeholder for an argument that can be passed | |
| // to a rule. It has no value and thus doesn't reference any other | |
| // variables. | |
| return nil | |
| } | |
| if err != nil { | |
| return err | |
| } | |
| l.variables[v] = value | |
| err = l.addNinjaStringDeps(value) | |
| if err != nil { | |
| return err | |
| } | |
| } | |
| return nil | |
| } | |
| func (l *liveTracker) addNinjaStringListDeps(list []ninjaString) error { | |
| for _, str := range list { | |
| err := l.addNinjaStringDeps(str) | |
| if err != nil { | |
| return err | |
| } | |
| } | |
| return nil | |
| } | |
| func (l *liveTracker) addNinjaStringDeps(str ninjaString) error { | |
| for _, v := range str.Variables() { | |
| err := l.addVariable(v) | |
| if err != nil { | |
| return err | |
| } | |
| } | |
| return nil | |
| } | |
| func (l *liveTracker) RemoveVariableIfLive(v Variable) bool { | |
| l.Lock() | |
| defer l.Unlock() | |
| _, isLive := l.variables[v] | |
| if isLive { | |
| delete(l.variables, v) | |
| } | |
| return isLive | |
| } | |
| func (l *liveTracker) RemoveRuleIfLive(r Rule) bool { | |
| l.Lock() | |
| defer l.Unlock() | |
| _, isLive := l.rules[r] | |
| if isLive { | |
| delete(l.rules, r) | |
| } | |
| return isLive | |
| } |