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	ctx    *Context    // Used to evaluate globs
27
28	variables map[Variable]*ninjaString
29	pools     map[Pool]*poolDef
30	rules     map[Rule]*ruleDef
31}
32
33func newLiveTracker(ctx *Context, config interface{}) *liveTracker {
34	return &liveTracker{
35		ctx:       ctx,
36		config:    config,
37		variables: make(map[Variable]*ninjaString),
38		pools:     make(map[Pool]*poolDef),
39		rules:     make(map[Rule]*ruleDef),
40	}
41}
42
43func (l *liveTracker) AddBuildDefDeps(def *buildDef) error {
44	l.Lock()
45	defer l.Unlock()
46
47	ruleDef, err := l.innerAddRule(def.Rule)
48	if err != nil {
49		return err
50	}
51	def.RuleDef = ruleDef
52
53	err = l.innerAddNinjaStringListDeps(def.Outputs)
54	if err != nil {
55		return err
56	}
57
58	err = l.innerAddNinjaStringListDeps(def.Inputs)
59	if err != nil {
60		return err
61	}
62
63	err = l.innerAddNinjaStringListDeps(def.Implicits)
64	if err != nil {
65		return err
66	}
67
68	err = l.innerAddNinjaStringListDeps(def.OrderOnly)
69	if err != nil {
70		return err
71	}
72
73	err = l.innerAddNinjaStringListDeps(def.Validations)
74	if err != nil {
75		return err
76	}
77
78	for _, value := range def.Variables {
79		err = l.innerAddNinjaStringDeps(value)
80		if err != nil {
81			return err
82		}
83	}
84
85	for _, value := range def.Args {
86		err = l.innerAddNinjaStringDeps(value)
87		if err != nil {
88			return err
89		}
90	}
91
92	return nil
93}
94
95func (l *liveTracker) addRule(r Rule) (def *ruleDef, err error) {
96	l.Lock()
97	defer l.Unlock()
98	return l.innerAddRule(r)
99}
100
101func (l *liveTracker) innerAddRule(r Rule) (def *ruleDef, err error) {
102	def, ok := l.rules[r]
103	if !ok {
104		def, err = r.def(l.config)
105		if err == errRuleIsBuiltin {
106			// No need to do anything for built-in rules.
107			return nil, nil
108		}
109		if err != nil {
110			return nil, err
111		}
112
113		if def.Pool != nil {
114			err = l.innerAddPool(def.Pool)
115			if err != nil {
116				return nil, err
117			}
118		}
119
120		err = l.innerAddNinjaStringListDeps(def.CommandDeps)
121		if err != nil {
122			return nil, err
123		}
124
125		err = l.innerAddNinjaStringListDeps(def.CommandOrderOnly)
126		if err != nil {
127			return nil, err
128		}
129
130		for _, value := range def.Variables {
131			err = l.innerAddNinjaStringDeps(value)
132			if err != nil {
133				return nil, err
134			}
135		}
136
137		l.rules[r] = def
138	}
139
140	return
141}
142
143func (l *liveTracker) addPool(p Pool) error {
144	l.Lock()
145	defer l.Unlock()
146	return l.addPool(p)
147}
148
149func (l *liveTracker) innerAddPool(p Pool) error {
150	_, ok := l.pools[p]
151	if !ok {
152		def, err := p.def(l.config)
153		if err == errPoolIsBuiltin {
154			// No need to do anything for built-in rules.
155			return nil
156		}
157		if err != nil {
158			return err
159		}
160
161		l.pools[p] = def
162	}
163
164	return nil
165}
166
167func (l *liveTracker) addVariable(v Variable) error {
168	l.Lock()
169	defer l.Unlock()
170	return l.innerAddVariable(v)
171}
172
173func (l *liveTracker) innerAddVariable(v Variable) error {
174	_, ok := l.variables[v]
175	if !ok {
176		ctx := &variableFuncContext{l.ctx}
177
178		value, err := v.value(ctx, l.config)
179		if err == errVariableIsArg {
180			// This variable is a placeholder for an argument that can be passed
181			// to a rule.  It has no value and thus doesn't reference any other
182			// variables.
183			return nil
184		}
185		if err != nil {
186			return err
187		}
188
189		l.variables[v] = value
190
191		err = l.innerAddNinjaStringDeps(value)
192		if err != nil {
193			return err
194		}
195	}
196
197	return nil
198}
199
200func (l *liveTracker) addNinjaStringListDeps(list []*ninjaString) error {
201	l.Lock()
202	defer l.Unlock()
203	return l.innerAddNinjaStringListDeps(list)
204}
205
206func (l *liveTracker) innerAddNinjaStringListDeps(list []*ninjaString) error {
207	for _, str := range list {
208		err := l.innerAddNinjaStringDeps(str)
209		if err != nil {
210			return err
211		}
212	}
213	return nil
214}
215
216func (l *liveTracker) addNinjaStringDeps(str *ninjaString) error {
217	l.Lock()
218	defer l.Unlock()
219	return l.innerAddNinjaStringDeps(str)
220}
221
222func (l *liveTracker) innerAddNinjaStringDeps(str *ninjaString) error {
223	for _, v := range str.Variables() {
224		err := l.innerAddVariable(v)
225		if err != nil {
226			return err
227		}
228	}
229	return nil
230}
231
232func (l *liveTracker) Eval(n *ninjaString) (string, error) {
233	l.Lock()
234	defer l.Unlock()
235	return n.Eval(l.variables)
236}
237
238func (l *liveTracker) RemoveVariableIfLive(v Variable) bool {
239	l.Lock()
240	defer l.Unlock()
241
242	_, isLive := l.variables[v]
243	if isLive {
244		delete(l.variables, v)
245	}
246	return isLive
247}
248
249func (l *liveTracker) RemoveRuleIfLive(r Rule) bool {
250	l.Lock()
251	defer l.Unlock()
252
253	_, isLive := l.rules[r]
254	if isLive {
255		delete(l.rules, r)
256	}
257	return isLive
258}
259