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