github.com/colincross/blueprint@v0.0.0-20150626231830-9c067caf2eb5/live_tracker.go (about)

     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  	err := l.addRule(def.Rule)
    46  	if err != nil {
    47  		return err
    48  	}
    49  
    50  	err = l.addNinjaStringListDeps(def.Outputs)
    51  	if err != nil {
    52  		return err
    53  	}
    54  
    55  	err = l.addNinjaStringListDeps(def.Inputs)
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	err = l.addNinjaStringListDeps(def.Implicits)
    61  	if err != nil {
    62  		return err
    63  	}
    64  
    65  	err = l.addNinjaStringListDeps(def.OrderOnly)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	for _, value := range def.Args {
    71  		err = l.addNinjaStringDeps(value)
    72  		if err != nil {
    73  			return err
    74  		}
    75  	}
    76  
    77  	return nil
    78  }
    79  
    80  func (l *liveTracker) addRule(r Rule) error {
    81  	_, ok := l.rules[r]
    82  	if !ok {
    83  		def, err := r.def(l.config)
    84  		if err == errRuleIsBuiltin {
    85  			// No need to do anything for built-in rules.
    86  			return nil
    87  		}
    88  		if err != nil {
    89  			return err
    90  		}
    91  
    92  		if def.Pool != nil {
    93  			err = l.addPool(def.Pool)
    94  			if err != nil {
    95  				return err
    96  			}
    97  		}
    98  
    99  		for _, value := range def.Variables {
   100  			err = l.addNinjaStringDeps(value)
   101  			if err != nil {
   102  				return err
   103  			}
   104  		}
   105  
   106  		l.rules[r] = def
   107  	}
   108  
   109  	return nil
   110  }
   111  
   112  func (l *liveTracker) addPool(p Pool) error {
   113  	_, ok := l.pools[p]
   114  	if !ok {
   115  		def, err := p.def(l.config)
   116  		if err == errPoolIsBuiltin {
   117  			// No need to do anything for built-in rules.
   118  			return nil
   119  		}
   120  		if err != nil {
   121  			return err
   122  		}
   123  
   124  		l.pools[p] = def
   125  	}
   126  
   127  	return nil
   128  }
   129  
   130  func (l *liveTracker) addVariable(v Variable) error {
   131  	_, ok := l.variables[v]
   132  	if !ok {
   133  		value, err := v.value(l.config)
   134  		if err == errVariableIsArg {
   135  			// This variable is a placeholder for an argument that can be passed
   136  			// to a rule.  It has no value and thus doesn't reference any other
   137  			// variables.
   138  			return nil
   139  		}
   140  		if err != nil {
   141  			return err
   142  		}
   143  
   144  		l.variables[v] = value
   145  
   146  		err = l.addNinjaStringDeps(value)
   147  		if err != nil {
   148  			return err
   149  		}
   150  	}
   151  
   152  	return nil
   153  }
   154  
   155  func (l *liveTracker) addNinjaStringListDeps(list []*ninjaString) error {
   156  	for _, str := range list {
   157  		err := l.addNinjaStringDeps(str)
   158  		if err != nil {
   159  			return err
   160  		}
   161  	}
   162  	return nil
   163  }
   164  
   165  func (l *liveTracker) addNinjaStringDeps(str *ninjaString) error {
   166  	for _, v := range str.variables {
   167  		err := l.addVariable(v)
   168  		if err != nil {
   169  			return err
   170  		}
   171  	}
   172  	return nil
   173  }
   174  
   175  func (l *liveTracker) RemoveVariableIfLive(v Variable) bool {
   176  	l.Lock()
   177  	defer l.Unlock()
   178  
   179  	_, isLive := l.variables[v]
   180  	if isLive {
   181  		delete(l.variables, v)
   182  	}
   183  	return isLive
   184  }
   185  
   186  func (l *liveTracker) RemoveRuleIfLive(r Rule) bool {
   187  	l.Lock()
   188  	defer l.Unlock()
   189  
   190  	_, isLive := l.rules[r]
   191  	if isLive {
   192  		delete(l.rules, r)
   193  	}
   194  	return isLive
   195  }