blob: 57eb2ca3824b19952f40894664d3cd5743179552 [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"
Martin Stjernholm191c25f2020-09-10 00:40:37 +010019 "reflect"
20 "strings"
Paul Duffinb645ec82019-11-27 17:43:54 +000021
22 "android/soong/android"
23)
24
25type bpPropertySet struct {
26 properties map[string]interface{}
Paul Duffin5b511a22020-01-15 14:23:52 +000027 tags map[string]android.BpPropertyTag
Paul Duffin0df49682021-05-07 01:10:01 +010028 comments map[string]string
Paul Duffinb645ec82019-11-27 17:43:54 +000029 order []string
30}
31
32var _ android.BpPropertySet = (*bpPropertySet)(nil)
33
34func (s *bpPropertySet) init() {
35 s.properties = make(map[string]interface{})
Paul Duffin5b511a22020-01-15 14:23:52 +000036 s.tags = make(map[string]android.BpPropertyTag)
Paul Duffinb645ec82019-11-27 17:43:54 +000037}
38
Martin Stjernholm191c25f2020-09-10 00:40:37 +010039// Converts the given value, which is assumed to be a struct, to a
40// bpPropertySet.
41func convertToPropertySet(value reflect.Value) *bpPropertySet {
42 res := newPropertySet()
43 structType := value.Type()
44
45 for i := 0; i < structType.NumField(); i++ {
46 field := structType.Field(i)
47 fieldVal := value.Field(i)
48
49 switch fieldVal.Type().Kind() {
50 case reflect.Ptr:
51 if fieldVal.IsNil() {
52 continue // nil pointer means the property isn't set.
53 }
54 fieldVal = fieldVal.Elem()
55 case reflect.Slice:
56 if fieldVal.IsNil() {
57 continue // Ignore a nil slice (but not one with length zero).
58 }
59 }
60
61 if fieldVal.Type().Kind() == reflect.Struct {
62 fieldVal = fieldVal.Addr() // Avoid struct copy below.
63 }
64 res.AddProperty(strings.ToLower(field.Name), fieldVal.Interface())
65 }
66
67 return res
68}
69
70// Converts the given value to something that can be set in a property.
71func coercePropertyValue(value interface{}) interface{} {
72 val := reflect.ValueOf(value)
73 switch val.Kind() {
74 case reflect.Struct:
75 // convertToPropertySet requires an addressable struct, and this is probably
76 // a mistake.
77 panic(fmt.Sprintf("Value is a struct, not a pointer to one: %v", value))
78 case reflect.Ptr:
79 if _, ok := value.(*bpPropertySet); !ok {
80 derefValue := reflect.Indirect(val)
81 if derefValue.Kind() != reflect.Struct {
82 panic(fmt.Sprintf("A pointer must be to a struct, got: %v", value))
83 }
84 return convertToPropertySet(derefValue)
85 }
86 }
87 return value
88}
89
90// Merges the fields of the given property set into s.
91func (s *bpPropertySet) mergePropertySet(propSet *bpPropertySet) {
92 for _, name := range propSet.order {
93 if tag, ok := propSet.tags[name]; ok {
94 s.AddPropertyWithTag(name, propSet.properties[name], tag)
95 } else {
96 s.AddProperty(name, propSet.properties[name])
97 }
98 }
99}
100
Paul Duffinb645ec82019-11-27 17:43:54 +0000101func (s *bpPropertySet) AddProperty(name string, value interface{}) {
Martin Stjernholm191c25f2020-09-10 00:40:37 +0100102 value = coercePropertyValue(value)
103
104 if propSetValue, ok := value.(*bpPropertySet); ok {
105 if curValue, ok := s.properties[name]; ok {
106 if curSet, ok := curValue.(*bpPropertySet); ok {
107 curSet.mergePropertySet(propSetValue)
108 return
109 }
110 // If the current value isn't a property set we got conflicting types.
111 // Continue down to the check below to complain about it.
112 }
113 }
114
Paul Duffinb645ec82019-11-27 17:43:54 +0000115 if s.properties[name] != nil {
Paul Duffin109c2ad2020-03-02 16:29:11 +0000116 panic(fmt.Sprintf("Property %q already exists in property set", name))
Paul Duffinb645ec82019-11-27 17:43:54 +0000117 }
118
119 s.properties[name] = value
120 s.order = append(s.order, name)
121}
122
Paul Duffin5b511a22020-01-15 14:23:52 +0000123func (s *bpPropertySet) AddPropertyWithTag(name string, value interface{}, tag android.BpPropertyTag) {
124 s.AddProperty(name, value)
125 s.tags[name] = tag
126}
127
Paul Duffinb645ec82019-11-27 17:43:54 +0000128func (s *bpPropertySet) AddPropertySet(name string) android.BpPropertySet {
Martin Stjernholm191c25f2020-09-10 00:40:37 +0100129 s.AddProperty(name, newPropertySet())
130 return s.properties[name].(android.BpPropertySet)
Paul Duffinb645ec82019-11-27 17:43:54 +0000131}
132
133func (s *bpPropertySet) getValue(name string) interface{} {
134 return s.properties[name]
135}
136
Paul Duffin0df49682021-05-07 01:10:01 +0100137func (s *bpPropertySet) getOptionalValue(name string) (interface{}, bool) {
138 value, ok := s.properties[name]
139 return value, ok
140}
141
Paul Duffin5b511a22020-01-15 14:23:52 +0000142func (s *bpPropertySet) getTag(name string) interface{} {
143 return s.tags[name]
144}
145
Paul Duffin0df49682021-05-07 01:10:01 +0100146func (s *bpPropertySet) AddCommentForProperty(name, text string) {
147 if s.comments == nil {
148 s.comments = map[string]string{}
149 }
150 s.comments[name] = strings.TrimSpace(text)
151}
152
Paul Duffin047fdca2020-02-21 16:06:25 +0000153func (s *bpPropertySet) transformContents(transformer bpPropertyTransformer) {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000154 var newOrder []string
155 for _, name := range s.order {
156 value := s.properties[name]
Paul Duffin5b511a22020-01-15 14:23:52 +0000157 tag := s.tags[name]
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000158 var newValue interface{}
Paul Duffin5b511a22020-01-15 14:23:52 +0000159 var newTag android.BpPropertyTag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000160 if propertySet, ok := value.(*bpPropertySet); ok {
Paul Duffin047fdca2020-02-21 16:06:25 +0000161 var newPropertySet *bpPropertySet
162 newPropertySet, newTag = transformPropertySet(transformer, name, propertySet, tag)
163 if newPropertySet == nil {
164 newValue = nil
165 } else {
166 newValue = newPropertySet
167 }
Paul Duffincc72e982020-01-14 15:53:11 +0000168 } else {
Paul Duffin5b511a22020-01-15 14:23:52 +0000169 newValue, newTag = transformer.transformProperty(name, value, tag)
Paul Duffincc72e982020-01-14 15:53:11 +0000170 }
Paul Duffinb645ec82019-11-27 17:43:54 +0000171
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000172 if newValue == nil {
173 // Delete the property from the map and exclude it from the new order.
174 delete(s.properties, name)
175 } else {
176 // Update the property in the map and add the name to the new order list.
177 s.properties[name] = newValue
Paul Duffin5b511a22020-01-15 14:23:52 +0000178 s.tags[name] = newTag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000179 newOrder = append(newOrder, name)
180 }
Paul Duffinb645ec82019-11-27 17:43:54 +0000181 }
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000182 s.order = newOrder
Paul Duffinb645ec82019-11-27 17:43:54 +0000183}
184
Paul Duffin047fdca2020-02-21 16:06:25 +0000185func transformPropertySet(transformer bpPropertyTransformer, name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
Paul Duffin180a0062020-02-21 16:06:25 +0000186 newPropertySet, newTag := transformer.transformPropertySetBeforeContents(name, propertySet, tag)
Paul Duffin047fdca2020-02-21 16:06:25 +0000187 if newPropertySet != nil {
188 newPropertySet.transformContents(transformer)
Paul Duffin180a0062020-02-21 16:06:25 +0000189
190 newPropertySet, newTag = transformer.transformPropertySetAfterContents(name, newPropertySet, newTag)
Paul Duffin047fdca2020-02-21 16:06:25 +0000191 }
192 return newPropertySet, newTag
193}
194
Paul Duffinb645ec82019-11-27 17:43:54 +0000195func (s *bpPropertySet) setProperty(name string, value interface{}) {
196 if s.properties[name] == nil {
197 s.AddProperty(name, value)
198 } else {
199 s.properties[name] = value
Paul Duffin5b511a22020-01-15 14:23:52 +0000200 s.tags[name] = nil
Paul Duffinb645ec82019-11-27 17:43:54 +0000201 }
202}
203
Paul Duffin83ad9562021-05-10 23:49:04 +0100204func (s *bpPropertySet) removeProperty(name string) {
205 delete(s.properties, name)
206 delete(s.tags, name)
207 _, s.order = android.RemoveFromList(name, s.order)
208}
209
Paul Duffinb645ec82019-11-27 17:43:54 +0000210func (s *bpPropertySet) insertAfter(position string, name string, value interface{}) {
211 if s.properties[name] != nil {
212 panic("Property %q already exists in property set")
213 }
214
215 // Add the name to the end of the order, to ensure it has necessary capacity
216 // and to handle the case when the position does not exist.
217 s.order = append(s.order, name)
218
219 // Search through the order for the item that matches supplied position. If
220 // found then insert the name of the new property after it.
221 for i, v := range s.order {
222 if v == position {
223 // Copy the items after the one where the new property should be inserted.
224 copy(s.order[i+2:], s.order[i+1:])
225 // Insert the item in the list.
226 s.order[i+1] = name
227 }
228 }
229
230 s.properties[name] = value
231}
232
233type bpModule struct {
Paul Duffincc72e982020-01-14 15:53:11 +0000234 *bpPropertySet
Paul Duffinb645ec82019-11-27 17:43:54 +0000235 moduleType string
236}
237
Paul Duffin0df49682021-05-07 01:10:01 +0100238func (m *bpModule) ModuleType() string {
239 return m.moduleType
240}
241
242func (m *bpModule) Name() string {
243 name, hasName := m.getOptionalValue("name")
244 if hasName {
245 return name.(string)
246 } else {
247 return ""
248 }
249}
250
Paul Duffinb645ec82019-11-27 17:43:54 +0000251var _ android.BpModule = (*bpModule)(nil)
252
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000253type bpPropertyTransformer interface {
Paul Duffin5b511a22020-01-15 14:23:52 +0000254 // Transform the property set, returning the new property set/tag to insert back into the
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000255 // parent property set (or module if this is the top level property set).
256 //
257 // This will be called before transforming the properties in the supplied set.
258 //
259 // The name will be "" for the top level property set.
260 //
Paul Duffin5b511a22020-01-15 14:23:52 +0000261 // Returning (nil, ...) will cause the property set to be removed.
Paul Duffin180a0062020-02-21 16:06:25 +0000262 transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
263
264 // Transform the property set, returning the new property set/tag to insert back into the
265 // parent property set (or module if this is the top level property set).
266 //
267 // This will be called after transforming the properties in the supplied set.
268 //
269 // The name will be "" for the top level property set.
270 //
271 // Returning (nil, ...) will cause the property set to be removed.
272 transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000273
Paul Duffin5b511a22020-01-15 14:23:52 +0000274 // Transform a property, return the new value/tag to insert back into the property set.
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000275 //
Paul Duffin5b511a22020-01-15 14:23:52 +0000276 // Returning (nil, ...) will cause the property to be removed.
277 transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000278}
279
280// Interface for transforming bpModule objects.
281type bpTransformer interface {
282 // Transform the module, returning the result.
283 //
284 // The method can either create a new module and return that, or modify the supplied module
285 // in place and return that.
286 //
287 // After this returns the transformer is applied to the contents of the returned module.
288 transformModule(module *bpModule) *bpModule
289
290 bpPropertyTransformer
291}
292
293type identityTransformation struct{}
294
295var _ bpTransformer = (*identityTransformation)(nil)
296
297func (t identityTransformation) transformModule(module *bpModule) *bpModule {
298 return module
299}
300
Paul Duffinb01ac4b2022-05-24 20:10:05 +0000301func (t identityTransformation) transformPropertySetBeforeContents(_ string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
Paul Duffin180a0062020-02-21 16:06:25 +0000302 return propertySet, tag
303}
304
Paul Duffinb01ac4b2022-05-24 20:10:05 +0000305func (t identityTransformation) transformPropertySetAfterContents(_ string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
Paul Duffin5b511a22020-01-15 14:23:52 +0000306 return propertySet, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000307}
308
Paul Duffinb01ac4b2022-05-24 20:10:05 +0000309func (t identityTransformation) transformProperty(_ string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
Paul Duffin5b511a22020-01-15 14:23:52 +0000310 return value, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000311}
312
Paul Duffincc72e982020-01-14 15:53:11 +0000313func (m *bpModule) deepCopy() *bpModule {
Sam Delmerico35881362023-06-30 14:40:10 -0400314 return transformModule(m, deepCopyTransformer)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000315}
316
Sam Delmerico35881362023-06-30 14:40:10 -0400317func transformModule(m *bpModule, transformer bpTransformer) *bpModule {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000318 transformedModule := transformer.transformModule(m)
Sam Delmerico35881362023-06-30 14:40:10 -0400319 if transformedModule != nil {
320 // Copy the contents of the returned property set into the module and then transform that.
321 transformedModule.bpPropertySet, _ = transformPropertySet(transformer, "", transformedModule.bpPropertySet, nil)
322 }
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000323 return transformedModule
324}
325
Paul Duffin180a0062020-02-21 16:06:25 +0000326type deepCopyTransformation struct {
327 identityTransformation
328}
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000329
330func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
331 // Take a shallow copy of the module. Any mutable property values will be copied by the
332 // transformer.
333 moduleCopy := *module
334 return &moduleCopy
335}
336
Paul Duffinb01ac4b2022-05-24 20:10:05 +0000337func (t deepCopyTransformation) transformPropertySetBeforeContents(_ string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000338 // Create a shallow copy of the properties map. Any mutable property values will be copied by the
339 // transformer.
340 propertiesCopy := make(map[string]interface{})
Paul Duffin5b511a22020-01-15 14:23:52 +0000341 for propertyName, value := range propertySet.properties {
342 propertiesCopy[propertyName] = value
343 }
344
345 // Ditto for tags map.
346 tagsCopy := make(map[string]android.BpPropertyTag)
347 for propertyName, propertyTag := range propertySet.tags {
348 tagsCopy[propertyName] = propertyTag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000349 }
350
351 // Create a new property set.
352 return &bpPropertySet{
353 properties: propertiesCopy,
Paul Duffin5b511a22020-01-15 14:23:52 +0000354 tags: tagsCopy,
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000355 order: append([]string(nil), propertySet.order...),
Paul Duffin5b511a22020-01-15 14:23:52 +0000356 }, tag
Paul Duffinb645ec82019-11-27 17:43:54 +0000357}
358
Paul Duffinb01ac4b2022-05-24 20:10:05 +0000359func (t deepCopyTransformation) transformProperty(_ string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000360 // Copy string slice, otherwise return value.
361 if values, ok := value.([]string); ok {
362 valuesCopy := make([]string, len(values))
363 copy(valuesCopy, values)
Paul Duffin5b511a22020-01-15 14:23:52 +0000364 return valuesCopy, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000365 }
Paul Duffin5b511a22020-01-15 14:23:52 +0000366 return value, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000367}
368
369var deepCopyTransformer bpTransformer = deepCopyTransformation{}
370
Paul Duffinb645ec82019-11-27 17:43:54 +0000371// A .bp file
372type bpFile struct {
373 modules map[string]*bpModule
374 order []*bpModule
375}
376
Paul Duffinb01ac4b2022-05-24 20:10:05 +0000377// AddModule adds a module to this.
Paul Duffinb645ec82019-11-27 17:43:54 +0000378//
379// The module must have had its "name" property set to a string value that
380// is unique within this file.
381func (f *bpFile) AddModule(module android.BpModule) {
382 m := module.(*bpModule)
Paul Duffin0df49682021-05-07 01:10:01 +0100383 moduleType := module.ModuleType()
384 name := m.Name()
385 hasName := true
386 if name == "" {
387 // Use a prefixed module type as the name instead just in case this is something like a package
388 // of namespace module which does not require a name.
389 name = "#" + moduleType
390 hasName = false
Paul Duffinb645ec82019-11-27 17:43:54 +0000391 }
Paul Duffin0df49682021-05-07 01:10:01 +0100392
393 if f.modules[name] != nil {
394 if hasName {
395 panic(fmt.Sprintf("Module %q already exists in bp file", name))
396 } else {
397 panic(fmt.Sprintf("Unnamed module type %q already exists in bp file", moduleType))
398 }
399 }
400
401 f.modules[name] = m
402 f.order = append(f.order, m)
Paul Duffinb645ec82019-11-27 17:43:54 +0000403}
404
405func (f *bpFile) newModule(moduleType string) *bpModule {
Paul Duffin047fdca2020-02-21 16:06:25 +0000406 return newModule(moduleType)
407}
408
409func newModule(moduleType string) *bpModule {
Paul Duffinb645ec82019-11-27 17:43:54 +0000410 module := &bpModule{
Paul Duffincc72e982020-01-14 15:53:11 +0000411 moduleType: moduleType,
Paul Duffin047fdca2020-02-21 16:06:25 +0000412 bpPropertySet: newPropertySet(),
Paul Duffinb645ec82019-11-27 17:43:54 +0000413 }
Paul Duffinb645ec82019-11-27 17:43:54 +0000414 return module
415}
Paul Duffin047fdca2020-02-21 16:06:25 +0000416
417func newPropertySet() *bpPropertySet {
418 set := &bpPropertySet{}
419 set.init()
420 return set
421}