| // 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. |
| |
| variables map[Variable]*ninjaString |
| pools map[Pool]*poolDef |
| rules map[Rule]*ruleDef |
| } |
| |
| func newLiveTracker(config interface{}) *liveTracker { |
| return &liveTracker{ |
| 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() |
| |
| err := l.addRule(def.Rule) |
| if err != nil { |
| return err |
| } |
| |
| 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 |
| } |
| |
| for _, value := range def.Args { |
| err = l.addNinjaStringDeps(value) |
| if err != nil { |
| return err |
| } |
| } |
| |
| return nil |
| } |
| |
| func (l *liveTracker) addRule(r Rule) error { |
| _, 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 |
| } |
| if err != nil { |
| return err |
| } |
| |
| if def.Pool != nil { |
| err = l.addPool(def.Pool) |
| if err != nil { |
| return err |
| } |
| } |
| |
| for _, value := range def.Variables { |
| err = l.addNinjaStringDeps(value) |
| if err != nil { |
| return err |
| } |
| } |
| |
| l.rules[r] = def |
| } |
| |
| return nil |
| } |
| |
| 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 { |
| value, err := v.value(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 |
| } |