blob: 68fe7ab4ebf5230aa42ad1bebfb3ebfb222db3d6 [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 {
Paul Duffin109c2ad2020-03-02 16:29:11 +000038 panic(fmt.Sprintf("Property %q already exists in property set", name))
Paul Duffinb645ec82019-11-27 17:43:54 +000039 }
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) {
Paul Duffin180a0062020-02-21 16:06:25 +000097 newPropertySet, newTag := transformer.transformPropertySetBeforeContents(name, propertySet, tag)
Paul Duffin047fdca2020-02-21 16:06:25 +000098 if newPropertySet != nil {
99 newPropertySet.transformContents(transformer)
Paul Duffin180a0062020-02-21 16:06:25 +0000100
101 newPropertySet, newTag = transformer.transformPropertySetAfterContents(name, newPropertySet, newTag)
Paul Duffin047fdca2020-02-21 16:06:25 +0000102 }
103 return newPropertySet, newTag
104}
105
Paul Duffinb645ec82019-11-27 17:43:54 +0000106func (s *bpPropertySet) setProperty(name string, value interface{}) {
107 if s.properties[name] == nil {
108 s.AddProperty(name, value)
109 } else {
110 s.properties[name] = value
Paul Duffin5b511a22020-01-15 14:23:52 +0000111 s.tags[name] = nil
Paul Duffinb645ec82019-11-27 17:43:54 +0000112 }
113}
114
115func (s *bpPropertySet) insertAfter(position string, name string, value interface{}) {
116 if s.properties[name] != nil {
117 panic("Property %q already exists in property set")
118 }
119
120 // Add the name to the end of the order, to ensure it has necessary capacity
121 // and to handle the case when the position does not exist.
122 s.order = append(s.order, name)
123
124 // Search through the order for the item that matches supplied position. If
125 // found then insert the name of the new property after it.
126 for i, v := range s.order {
127 if v == position {
128 // Copy the items after the one where the new property should be inserted.
129 copy(s.order[i+2:], s.order[i+1:])
130 // Insert the item in the list.
131 s.order[i+1] = name
132 }
133 }
134
135 s.properties[name] = value
136}
137
138type bpModule struct {
Paul Duffincc72e982020-01-14 15:53:11 +0000139 *bpPropertySet
Paul Duffinb645ec82019-11-27 17:43:54 +0000140 moduleType string
141}
142
143var _ android.BpModule = (*bpModule)(nil)
144
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000145type bpPropertyTransformer interface {
Paul Duffin5b511a22020-01-15 14:23:52 +0000146 // Transform the property set, returning the new property set/tag to insert back into the
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000147 // parent property set (or module if this is the top level property set).
148 //
149 // This will be called before transforming the properties in the supplied set.
150 //
151 // The name will be "" for the top level property set.
152 //
Paul Duffin5b511a22020-01-15 14:23:52 +0000153 // Returning (nil, ...) will cause the property set to be removed.
Paul Duffin180a0062020-02-21 16:06:25 +0000154 transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
155
156 // Transform the property set, returning the new property set/tag to insert back into the
157 // parent property set (or module if this is the top level property set).
158 //
159 // This will be called after transforming the properties in the supplied set.
160 //
161 // The name will be "" for the top level property set.
162 //
163 // Returning (nil, ...) will cause the property set to be removed.
164 transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000165
Paul Duffin5b511a22020-01-15 14:23:52 +0000166 // Transform a property, return the new value/tag to insert back into the property set.
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000167 //
Paul Duffin5b511a22020-01-15 14:23:52 +0000168 // Returning (nil, ...) will cause the property to be removed.
169 transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000170}
171
172// Interface for transforming bpModule objects.
173type bpTransformer interface {
174 // Transform the module, returning the result.
175 //
176 // The method can either create a new module and return that, or modify the supplied module
177 // in place and return that.
178 //
179 // After this returns the transformer is applied to the contents of the returned module.
180 transformModule(module *bpModule) *bpModule
181
182 bpPropertyTransformer
183}
184
185type identityTransformation struct{}
186
187var _ bpTransformer = (*identityTransformation)(nil)
188
189func (t identityTransformation) transformModule(module *bpModule) *bpModule {
190 return module
191}
192
Paul Duffin180a0062020-02-21 16:06:25 +0000193func (t identityTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
194 return propertySet, tag
195}
196
197func (t identityTransformation) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
Paul Duffin5b511a22020-01-15 14:23:52 +0000198 return propertySet, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000199}
200
Paul Duffin5b511a22020-01-15 14:23:52 +0000201func (t identityTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
202 return value, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000203}
204
Paul Duffincc72e982020-01-14 15:53:11 +0000205func (m *bpModule) deepCopy() *bpModule {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000206 return m.transform(deepCopyTransformer)
207}
208
209func (m *bpModule) transform(transformer bpTransformer) *bpModule {
210 transformedModule := transformer.transformModule(m)
211 // Copy the contents of the returned property set into the module and then transform that.
Paul Duffin047fdca2020-02-21 16:06:25 +0000212 transformedModule.bpPropertySet, _ = transformPropertySet(transformer, "", transformedModule.bpPropertySet, nil)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000213 return transformedModule
214}
215
Paul Duffin180a0062020-02-21 16:06:25 +0000216type deepCopyTransformation struct {
217 identityTransformation
218}
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000219
220func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
221 // Take a shallow copy of the module. Any mutable property values will be copied by the
222 // transformer.
223 moduleCopy := *module
224 return &moduleCopy
225}
226
Paul Duffin180a0062020-02-21 16:06:25 +0000227func (t deepCopyTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000228 // Create a shallow copy of the properties map. Any mutable property values will be copied by the
229 // transformer.
230 propertiesCopy := make(map[string]interface{})
Paul Duffin5b511a22020-01-15 14:23:52 +0000231 for propertyName, value := range propertySet.properties {
232 propertiesCopy[propertyName] = value
233 }
234
235 // Ditto for tags map.
236 tagsCopy := make(map[string]android.BpPropertyTag)
237 for propertyName, propertyTag := range propertySet.tags {
238 tagsCopy[propertyName] = propertyTag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000239 }
240
241 // Create a new property set.
242 return &bpPropertySet{
243 properties: propertiesCopy,
Paul Duffin5b511a22020-01-15 14:23:52 +0000244 tags: tagsCopy,
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000245 order: append([]string(nil), propertySet.order...),
Paul Duffin5b511a22020-01-15 14:23:52 +0000246 }, tag
Paul Duffinb645ec82019-11-27 17:43:54 +0000247}
248
Paul Duffin5b511a22020-01-15 14:23:52 +0000249func (t deepCopyTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000250 // Copy string slice, otherwise return value.
251 if values, ok := value.([]string); ok {
252 valuesCopy := make([]string, len(values))
253 copy(valuesCopy, values)
Paul Duffin5b511a22020-01-15 14:23:52 +0000254 return valuesCopy, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000255 }
Paul Duffin5b511a22020-01-15 14:23:52 +0000256 return value, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000257}
258
259var deepCopyTransformer bpTransformer = deepCopyTransformation{}
260
Paul Duffinb645ec82019-11-27 17:43:54 +0000261// A .bp file
262type bpFile struct {
263 modules map[string]*bpModule
264 order []*bpModule
265}
266
267// Add a module.
268//
269// The module must have had its "name" property set to a string value that
270// is unique within this file.
271func (f *bpFile) AddModule(module android.BpModule) {
272 m := module.(*bpModule)
273 if name, ok := m.getValue("name").(string); ok {
274 if f.modules[name] != nil {
275 panic(fmt.Sprintf("Module %q already exists in bp file", name))
276 }
277
278 f.modules[name] = m
279 f.order = append(f.order, m)
280 } else {
281 panic("Module does not have a name property, or it is not a string")
282 }
283}
284
285func (f *bpFile) newModule(moduleType string) *bpModule {
Paul Duffin047fdca2020-02-21 16:06:25 +0000286 return newModule(moduleType)
287}
288
289func newModule(moduleType string) *bpModule {
Paul Duffinb645ec82019-11-27 17:43:54 +0000290 module := &bpModule{
Paul Duffincc72e982020-01-14 15:53:11 +0000291 moduleType: moduleType,
Paul Duffin047fdca2020-02-21 16:06:25 +0000292 bpPropertySet: newPropertySet(),
Paul Duffinb645ec82019-11-27 17:43:54 +0000293 }
Paul Duffinb645ec82019-11-27 17:43:54 +0000294 return module
295}
Paul Duffin047fdca2020-02-21 16:06:25 +0000296
297func newPropertySet() *bpPropertySet {
298 set := &bpPropertySet{}
299 set.init()
300 return set
301}