Home | History | Annotate | Download | only in blueprint
      1 // Copyright 2014 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package blueprint
     16 
     17 import "sync"
     18 
     19 // A liveTracker tracks the values of live variables, rules, and pools.  An
     20 // entity is made "live" when it is referenced directly or indirectly by a build
     21 // definition.  When an entity is made live its value is computed based on the
     22 // configuration.
     23 type liveTracker struct {
     24 	sync.Mutex
     25 	config interface{} // Used to evaluate variable, rule, and pool values.
     26 
     27 	variables map[Variable]*ninjaString
     28 	pools     map[Pool]*poolDef
     29 	rules     map[Rule]*ruleDef
     30 }
     31 
     32 func newLiveTracker(config interface{}) *liveTracker {
     33 	return &liveTracker{
     34 		config:    config,
     35 		variables: make(map[Variable]*ninjaString),
     36 		pools:     make(map[Pool]*poolDef),
     37 		rules:     make(map[Rule]*ruleDef),
     38 	}
     39 }
     40 
     41 func (l *liveTracker) AddBuildDefDeps(def *buildDef) error {
     42 	l.Lock()
     43 	defer l.Unlock()
     44 
     45 	ruleDef, err := l.addRule(def.Rule)
     46 	if err != nil {
     47 		return err
     48 	}
     49 	def.RuleDef = ruleDef
     50 
     51 	err = l.addNinjaStringListDeps(def.Outputs)
     52 	if err != nil {
     53 		return err
     54 	}
     55 
     56 	err = l.addNinjaStringListDeps(def.Inputs)
     57 	if err != nil {
     58 		return err
     59 	}
     60 
     61 	err = l.addNinjaStringListDeps(def.Implicits)
     62 	if err != nil {
     63 		return err
     64 	}
     65 
     66 	err = l.addNinjaStringListDeps(def.OrderOnly)
     67 	if err != nil {
     68 		return err
     69 	}
     70 
     71 	for _, value := range def.Args {
     72 		err = l.addNinjaStringDeps(value)
     73 		if err != nil {
     74 			return err
     75 		}
     76 	}
     77 
     78 	return nil
     79 }
     80 
     81 func (l *liveTracker) addRule(r Rule) (def *ruleDef, err error) {
     82 	def, ok := l.rules[r]
     83 	if !ok {
     84 		def, err = r.def(l.config)
     85 		if err == errRuleIsBuiltin {
     86 			// No need to do anything for built-in rules.
     87 			return nil, nil
     88 		}
     89 		if err != nil {
     90 			return nil, err
     91 		}
     92 
     93 		if def.Pool != nil {
     94 			err = l.addPool(def.Pool)
     95 			if err != nil {
     96 				return nil, err
     97 			}
     98 		}
     99 
    100 		err = l.addNinjaStringListDeps(def.CommandDeps)
    101 		if err != nil {
    102 			return nil, err
    103 		}
    104 
    105 		for _, value := range def.Variables {
    106 			err = l.addNinjaStringDeps(value)
    107 			if err != nil {
    108 				return nil, err
    109 			}
    110 		}
    111 
    112 		l.rules[r] = def
    113 	}
    114 
    115 	return
    116 }
    117 
    118 func (l *liveTracker) addPool(p Pool) error {
    119 	_, ok := l.pools[p]
    120 	if !ok {
    121 		def, err := p.def(l.config)
    122 		if err == errPoolIsBuiltin {
    123 			// No need to do anything for built-in rules.
    124 			return nil
    125 		}
    126 		if err != nil {
    127 			return err
    128 		}
    129 
    130 		l.pools[p] = def
    131 	}
    132 
    133 	return nil
    134 }
    135 
    136 func (l *liveTracker) addVariable(v Variable) error {
    137 	_, ok := l.variables[v]
    138 	if !ok {
    139 		value, err := v.value(l.config)
    140 		if err == errVariableIsArg {
    141 			// This variable is a placeholder for an argument that can be passed
    142 			// to a rule.  It has no value and thus doesn't reference any other
    143 			// variables.
    144 			return nil
    145 		}
    146 		if err != nil {
    147 			return err
    148 		}
    149 
    150 		l.variables[v] = value
    151 
    152 		err = l.addNinjaStringDeps(value)
    153 		if err != nil {
    154 			return err
    155 		}
    156 	}
    157 
    158 	return nil
    159 }
    160 
    161 func (l *liveTracker) addNinjaStringListDeps(list []*ninjaString) error {
    162 	for _, str := range list {
    163 		err := l.addNinjaStringDeps(str)
    164 		if err != nil {
    165 			return err
    166 		}
    167 	}
    168 	return nil
    169 }
    170 
    171 func (l *liveTracker) addNinjaStringDeps(str *ninjaString) error {
    172 	for _, v := range str.variables {
    173 		err := l.addVariable(v)
    174 		if err != nil {
    175 			return err
    176 		}
    177 	}
    178 	return nil
    179 }
    180 
    181 func (l *liveTracker) RemoveVariableIfLive(v Variable) bool {
    182 	l.Lock()
    183 	defer l.Unlock()
    184 
    185 	_, isLive := l.variables[v]
    186 	if isLive {
    187 		delete(l.variables, v)
    188 	}
    189 	return isLive
    190 }
    191 
    192 func (l *liveTracker) RemoveRuleIfLive(r Rule) bool {
    193 	l.Lock()
    194 	defer l.Unlock()
    195 
    196 	_, isLive := l.rules[r]
    197 	if isLive {
    198 		delete(l.rules, r)
    199 	}
    200 	return isLive
    201 }
    202