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.Args {
72		err = l.addNinjaStringDeps(value)
73		if err != nil {
74			return err
75		}
76	}
77
78	return nil
79}
80
81func (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
118func (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
136func (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
161func (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
171func (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
181func (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
192func (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