blob: 5c340cda342f936ab4d42a1fce1ef6000a583fc5 [file] [log] [blame]
Paul Duffinb645ec82019-11-27 17:43:54 +00001// Copyright (C) 2019 The Android Open Source Project
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 sdk
16
17import (
18 "fmt"
19
20 "android/soong/android"
21)
22
23type bpPropertySet struct {
24 properties map[string]interface{}
Paul Duffin5b511a22020-01-15 14:23:52 +000025 tags map[string]android.BpPropertyTag
Paul Duffinb645ec82019-11-27 17:43:54 +000026 order []string
27}
28
29var _ android.BpPropertySet = (*bpPropertySet)(nil)
30
31func (s *bpPropertySet) init() {
32 s.properties = make(map[string]interface{})
Paul Duffin5b511a22020-01-15 14:23:52 +000033 s.tags = make(map[string]android.BpPropertyTag)
Paul Duffinb645ec82019-11-27 17:43:54 +000034}
35
36func (s *bpPropertySet) AddProperty(name string, value interface{}) {
37 if s.properties[name] != nil {
38 panic("Property %q already exists in property set")
39 }
40
41 s.properties[name] = value
42 s.order = append(s.order, name)
43}
44
Paul Duffin5b511a22020-01-15 14:23:52 +000045func (s *bpPropertySet) AddPropertyWithTag(name string, value interface{}, tag android.BpPropertyTag) {
46 s.AddProperty(name, value)
47 s.tags[name] = tag
48}
49
Paul Duffinb645ec82019-11-27 17:43:54 +000050func (s *bpPropertySet) AddPropertySet(name string) android.BpPropertySet {
Paul Duffin047fdca2020-02-21 16:06:25 +000051 set := newPropertySet()
Paul Duffinb645ec82019-11-27 17:43:54 +000052 s.AddProperty(name, set)
53 return set
54}
55
56func (s *bpPropertySet) getValue(name string) interface{} {
57 return s.properties[name]
58}
59
Paul Duffin5b511a22020-01-15 14:23:52 +000060func (s *bpPropertySet) getTag(name string) interface{} {
61 return s.tags[name]
62}
63
Paul Duffin047fdca2020-02-21 16:06:25 +000064func (s *bpPropertySet) transformContents(transformer bpPropertyTransformer) {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000065 var newOrder []string
66 for _, name := range s.order {
67 value := s.properties[name]
Paul Duffin5b511a22020-01-15 14:23:52 +000068 tag := s.tags[name]
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000069 var newValue interface{}
Paul Duffin5b511a22020-01-15 14:23:52 +000070 var newTag android.BpPropertyTag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000071 if propertySet, ok := value.(*bpPropertySet); ok {
Paul Duffin047fdca2020-02-21 16:06:25 +000072 var newPropertySet *bpPropertySet
73 newPropertySet, newTag = transformPropertySet(transformer, name, propertySet, tag)
74 if newPropertySet == nil {
75 newValue = nil
76 } else {
77 newValue = newPropertySet
78 }
Paul Duffincc72e982020-01-14 15:53:11 +000079 } else {
Paul Duffin5b511a22020-01-15 14:23:52 +000080 newValue, newTag = transformer.transformProperty(name, value, tag)
Paul Duffincc72e982020-01-14 15:53:11 +000081 }
Paul Duffinb645ec82019-11-27 17:43:54 +000082
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000083 if newValue == nil {
84 // Delete the property from the map and exclude it from the new order.
85 delete(s.properties, name)
86 } else {
87 // Update the property in the map and add the name to the new order list.
88 s.properties[name] = newValue
Paul Duffin5b511a22020-01-15 14:23:52 +000089 s.tags[name] = newTag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000090 newOrder = append(newOrder, name)
91 }
Paul Duffinb645ec82019-11-27 17:43:54 +000092 }
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000093 s.order = newOrder
Paul Duffinb645ec82019-11-27 17:43:54 +000094}
95
Paul Duffin047fdca2020-02-21 16:06:25 +000096func transformPropertySet(transformer bpPropertyTransformer, name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
97 newPropertySet, newTag := transformer.transformPropertySet(name, propertySet, tag)
98 if newPropertySet != nil {
99 newPropertySet.transformContents(transformer)
100 }
101 return newPropertySet, newTag
102}
103
Paul Duffinb645ec82019-11-27 17:43:54 +0000104func (s *bpPropertySet) setProperty(name string, value interface{}) {
105 if s.properties[name] == nil {
106 s.AddProperty(name, value)
107 } else {
108 s.properties[name] = value
Paul Duffin5b511a22020-01-15 14:23:52 +0000109 s.tags[name] = nil
Paul Duffinb645ec82019-11-27 17:43:54 +0000110 }
111}
112
113func (s *bpPropertySet) insertAfter(position string, name string, value interface{}) {
114 if s.properties[name] != nil {
115 panic("Property %q already exists in property set")
116 }
117
118 // Add the name to the end of the order, to ensure it has necessary capacity
119 // and to handle the case when the position does not exist.
120 s.order = append(s.order, name)
121
122 // Search through the order for the item that matches supplied position. If
123 // found then insert the name of the new property after it.
124 for i, v := range s.order {
125 if v == position {
126 // Copy the items after the one where the new property should be inserted.
127 copy(s.order[i+2:], s.order[i+1:])
128 // Insert the item in the list.
129 s.order[i+1] = name
130 }
131 }
132
133 s.properties[name] = value
134}
135
136type bpModule struct {
Paul Duffincc72e982020-01-14 15:53:11 +0000137 *bpPropertySet
Paul Duffinb645ec82019-11-27 17:43:54 +0000138 moduleType string
139}
140
141var _ android.BpModule = (*bpModule)(nil)
142
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000143type bpPropertyTransformer interface {
Paul Duffin5b511a22020-01-15 14:23:52 +0000144 // Transform the property set, returning the new property set/tag to insert back into the
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000145 // parent property set (or module if this is the top level property set).
146 //
147 // This will be called before transforming the properties in the supplied set.
148 //
149 // The name will be "" for the top level property set.
150 //
Paul Duffin5b511a22020-01-15 14:23:52 +0000151 // Returning (nil, ...) will cause the property set to be removed.
152 transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000153
Paul Duffin5b511a22020-01-15 14:23:52 +0000154 // Transform a property, return the new value/tag to insert back into the property set.
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000155 //
Paul Duffin5b511a22020-01-15 14:23:52 +0000156 // Returning (nil, ...) will cause the property to be removed.
157 transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000158}
159
160// Interface for transforming bpModule objects.
161type bpTransformer interface {
162 // Transform the module, returning the result.
163 //
164 // The method can either create a new module and return that, or modify the supplied module
165 // in place and return that.
166 //
167 // After this returns the transformer is applied to the contents of the returned module.
168 transformModule(module *bpModule) *bpModule
169
170 bpPropertyTransformer
171}
172
173type identityTransformation struct{}
174
175var _ bpTransformer = (*identityTransformation)(nil)
176
177func (t identityTransformation) transformModule(module *bpModule) *bpModule {
178 return module
179}
180
Paul Duffin5b511a22020-01-15 14:23:52 +0000181func (t identityTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
182 return propertySet, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000183}
184
Paul Duffin5b511a22020-01-15 14:23:52 +0000185func (t identityTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
186 return value, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000187}
188
Paul Duffincc72e982020-01-14 15:53:11 +0000189func (m *bpModule) deepCopy() *bpModule {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000190 return m.transform(deepCopyTransformer)
191}
192
193func (m *bpModule) transform(transformer bpTransformer) *bpModule {
194 transformedModule := transformer.transformModule(m)
195 // Copy the contents of the returned property set into the module and then transform that.
Paul Duffin047fdca2020-02-21 16:06:25 +0000196 transformedModule.bpPropertySet, _ = transformPropertySet(transformer, "", transformedModule.bpPropertySet, nil)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000197 return transformedModule
198}
199
200type deepCopyTransformation struct{}
201
202func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
203 // Take a shallow copy of the module. Any mutable property values will be copied by the
204 // transformer.
205 moduleCopy := *module
206 return &moduleCopy
207}
208
Paul Duffin5b511a22020-01-15 14:23:52 +0000209func (t deepCopyTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000210 // Create a shallow copy of the properties map. Any mutable property values will be copied by the
211 // transformer.
212 propertiesCopy := make(map[string]interface{})
Paul Duffin5b511a22020-01-15 14:23:52 +0000213 for propertyName, value := range propertySet.properties {
214 propertiesCopy[propertyName] = value
215 }
216
217 // Ditto for tags map.
218 tagsCopy := make(map[string]android.BpPropertyTag)
219 for propertyName, propertyTag := range propertySet.tags {
220 tagsCopy[propertyName] = propertyTag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000221 }
222
223 // Create a new property set.
224 return &bpPropertySet{
225 properties: propertiesCopy,
Paul Duffin5b511a22020-01-15 14:23:52 +0000226 tags: tagsCopy,
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000227 order: append([]string(nil), propertySet.order...),
Paul Duffin5b511a22020-01-15 14:23:52 +0000228 }, tag
Paul Duffinb645ec82019-11-27 17:43:54 +0000229}
230
Paul Duffin5b511a22020-01-15 14:23:52 +0000231func (t deepCopyTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000232 // Copy string slice, otherwise return value.
233 if values, ok := value.([]string); ok {
234 valuesCopy := make([]string, len(values))
235 copy(valuesCopy, values)
Paul Duffin5b511a22020-01-15 14:23:52 +0000236 return valuesCopy, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000237 }
Paul Duffin5b511a22020-01-15 14:23:52 +0000238 return value, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000239}
240
241var deepCopyTransformer bpTransformer = deepCopyTransformation{}
242
Paul Duffinb645ec82019-11-27 17:43:54 +0000243// A .bp file
244type bpFile struct {
245 modules map[string]*bpModule
246 order []*bpModule
247}
248
249// Add a module.
250//
251// The module must have had its "name" property set to a string value that
252// is unique within this file.
253func (f *bpFile) AddModule(module android.BpModule) {
254 m := module.(*bpModule)
255 if name, ok := m.getValue("name").(string); ok {
256 if f.modules[name] != nil {
257 panic(fmt.Sprintf("Module %q already exists in bp file", name))
258 }
259
260 f.modules[name] = m
261 f.order = append(f.order, m)
262 } else {
263 panic("Module does not have a name property, or it is not a string")
264 }
265}
266
267func (f *bpFile) newModule(moduleType string) *bpModule {
Paul Duffin047fdca2020-02-21 16:06:25 +0000268 return newModule(moduleType)
269}
270
271func newModule(moduleType string) *bpModule {
Paul Duffinb645ec82019-11-27 17:43:54 +0000272 module := &bpModule{
Paul Duffincc72e982020-01-14 15:53:11 +0000273 moduleType: moduleType,
Paul Duffin047fdca2020-02-21 16:06:25 +0000274 bpPropertySet: newPropertySet(),
Paul Duffinb645ec82019-11-27 17:43:54 +0000275 }
Paul Duffinb645ec82019-11-27 17:43:54 +0000276 return module
277}
Paul Duffin047fdca2020-02-21 16:06:25 +0000278
279func newPropertySet() *bpPropertySet {
280 set := &bpPropertySet{}
281 set.init()
282 return set
283}