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
15package blueprint
16
17import "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.
23type 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
32func 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
41func (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	err = l.addNinjaStringListDeps(def.Validations)
72	if err != nil {
73		return err
74	}
75
76	for _, value := range def.Variables {
77		err = l.addNinjaStringDeps(value)
78		if err != nil {
79			return err
80		}
81	}
82
83	for _, value := range def.Args {
84		err = l.addNinjaStringDeps(value)
85		if err != nil {
86			return err
87		}
88	}
89
90	return nil
91}
92
93func (l *liveTracker) addRule(r Rule) (def *ruleDef, err error) {
94	def, ok := l.rules[r]
95	if !ok {
96		def, err = r.def(l.config)
97		if err == errRuleIsBuiltin {
98			// No need to do anything for built-in rules.
99			return nil, nil
100		}
101		if err != nil {
102			return nil, err
103		}
104
105		if def.Pool != nil {
106			err = l.addPool(def.Pool)
107			if err != nil {
108				return nil, err
109			}
110		}
111
112		err = l.addNinjaStringListDeps(def.CommandDeps)
113		if err != nil {
114			return nil, err
115		}
116
117		err = l.addNinjaStringListDeps(def.CommandOrderOnly)
118		if err != nil {
119			return nil, err
120		}
121
122		for _, value := range def.Variables {
123			err = l.addNinjaStringDeps(value)
124			if err != nil {
125				return nil, err
126			}
127		}
128
129		l.rules[r] = def
130	}
131
132	return
133}
134
135func (l *liveTracker) addPool(p Pool) error {
136	_, ok := l.pools[p]
137	if !ok {
138		def, err := p.def(l.config)
139		if err == errPoolIsBuiltin {
140			// No need to do anything for built-in rules.
141			return nil
142		}
143		if err != nil {
144			return err
145		}
146
147		l.pools[p] = def
148	}
149
150	return nil
151}
152
153func (l *liveTracker) addVariable(v Variable) error {
154	_, ok := l.variables[v]
155	if !ok {
156		value, err := v.value(l.config)
157		if err == errVariableIsArg {
158			// This variable is a placeholder for an argument that can be passed
159			// to a rule.  It has no value and thus doesn't reference any other
160			// variables.
161			return nil
162		}
163		if err != nil {
164			return err
165		}
166
167		l.variables[v] = value
168
169		err = l.addNinjaStringDeps(value)
170		if err != nil {
171			return err
172		}
173	}
174
175	return nil
176}
177
178func (l *liveTracker) addNinjaStringListDeps(list []ninjaString) error {
179	for _, str := range list {
180		err := l.addNinjaStringDeps(str)
181		if err != nil {
182			return err
183		}
184	}
185	return nil
186}
187
188func (l *liveTracker) addNinjaStringDeps(str ninjaString) error {
189	for _, v := range str.Variables() {
190		err := l.addVariable(v)
191		if err != nil {
192			return err
193		}
194	}
195	return nil
196}
197
198func (l *liveTracker) RemoveVariableIfLive(v Variable) bool {
199	l.Lock()
200	defer l.Unlock()
201
202	_, isLive := l.variables[v]
203	if isLive {
204		delete(l.variables, v)
205	}
206	return isLive
207}
208
209func (l *liveTracker) RemoveRuleIfLive(r Rule) bool {
210	l.Lock()
211	defer l.Unlock()
212
213	_, isLive := l.rules[r]
214	if isLive {
215		delete(l.rules, r)
216	}
217	return isLive
218}
219