blob: 6936daf9472d9d66a8ee0fe54b8a5efb86598a1d [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 {
51 set := &bpPropertySet{}
52 set.init()
53 s.AddProperty(name, set)
54 return set
55}
56
57func (s *bpPropertySet) getValue(name string) interface{} {
58 return s.properties[name]
59}
60
Paul Duffin5b511a22020-01-15 14:23:52 +000061func (s *bpPropertySet) getTag(name string) interface{} {
62 return s.tags[name]
63}
64
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000065func (s *bpPropertySet) transform(transformer bpPropertyTransformer) {
66 var newOrder []string
67 for _, name := range s.order {
68 value := s.properties[name]
Paul Duffin5b511a22020-01-15 14:23:52 +000069 tag := s.tags[name]
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000070 var newValue interface{}
Paul Duffin5b511a22020-01-15 14:23:52 +000071 var newTag android.BpPropertyTag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000072 if propertySet, ok := value.(*bpPropertySet); ok {
Paul Duffin5b511a22020-01-15 14:23:52 +000073 newValue, newTag = transformer.transformPropertySet(name, propertySet, tag)
Paul Duffincc72e982020-01-14 15:53:11 +000074 } else {
Paul Duffin5b511a22020-01-15 14:23:52 +000075 newValue, newTag = transformer.transformProperty(name, value, tag)
Paul Duffincc72e982020-01-14 15:53:11 +000076 }
Paul Duffinb645ec82019-11-27 17:43:54 +000077
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000078 if newValue == nil {
79 // Delete the property from the map and exclude it from the new order.
80 delete(s.properties, name)
81 } else {
82 // Update the property in the map and add the name to the new order list.
83 s.properties[name] = newValue
Paul Duffin5b511a22020-01-15 14:23:52 +000084 s.tags[name] = newTag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000085 newOrder = append(newOrder, name)
86 }
Paul Duffinb645ec82019-11-27 17:43:54 +000087 }
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000088 s.order = newOrder
Paul Duffinb645ec82019-11-27 17:43:54 +000089}
90
91func (s *bpPropertySet) setProperty(name string, value interface{}) {
92 if s.properties[name] == nil {
93 s.AddProperty(name, value)
94 } else {
95 s.properties[name] = value
Paul Duffin5b511a22020-01-15 14:23:52 +000096 s.tags[name] = nil
Paul Duffinb645ec82019-11-27 17:43:54 +000097 }
98}
99
100func (s *bpPropertySet) insertAfter(position string, name string, value interface{}) {
101 if s.properties[name] != nil {
102 panic("Property %q already exists in property set")
103 }
104
105 // Add the name to the end of the order, to ensure it has necessary capacity
106 // and to handle the case when the position does not exist.
107 s.order = append(s.order, name)
108
109 // Search through the order for the item that matches supplied position. If
110 // found then insert the name of the new property after it.
111 for i, v := range s.order {
112 if v == position {
113 // Copy the items after the one where the new property should be inserted.
114 copy(s.order[i+2:], s.order[i+1:])
115 // Insert the item in the list.
116 s.order[i+1] = name
117 }
118 }
119
120 s.properties[name] = value
121}
122
123type bpModule struct {
Paul Duffincc72e982020-01-14 15:53:11 +0000124 *bpPropertySet
Paul Duffinb645ec82019-11-27 17:43:54 +0000125 moduleType string
126}
127
128var _ android.BpModule = (*bpModule)(nil)
129
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000130type bpPropertyTransformer interface {
Paul Duffin5b511a22020-01-15 14:23:52 +0000131 // Transform the property set, returning the new property set/tag to insert back into the
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000132 // parent property set (or module if this is the top level property set).
133 //
134 // This will be called before transforming the properties in the supplied set.
135 //
136 // The name will be "" for the top level property set.
137 //
Paul Duffin5b511a22020-01-15 14:23:52 +0000138 // Returning (nil, ...) will cause the property set to be removed.
139 transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000140
Paul Duffin5b511a22020-01-15 14:23:52 +0000141 // Transform a property, return the new value/tag to insert back into the property set.
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000142 //
Paul Duffin5b511a22020-01-15 14:23:52 +0000143 // Returning (nil, ...) will cause the property to be removed.
144 transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000145}
146
147// Interface for transforming bpModule objects.
148type bpTransformer interface {
149 // Transform the module, returning the result.
150 //
151 // The method can either create a new module and return that, or modify the supplied module
152 // in place and return that.
153 //
154 // After this returns the transformer is applied to the contents of the returned module.
155 transformModule(module *bpModule) *bpModule
156
157 bpPropertyTransformer
158}
159
160type identityTransformation struct{}
161
162var _ bpTransformer = (*identityTransformation)(nil)
163
164func (t identityTransformation) transformModule(module *bpModule) *bpModule {
165 return module
166}
167
Paul Duffin5b511a22020-01-15 14:23:52 +0000168func (t identityTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
169 return propertySet, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000170}
171
Paul Duffin5b511a22020-01-15 14:23:52 +0000172func (t identityTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
173 return value, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000174}
175
Paul Duffincc72e982020-01-14 15:53:11 +0000176func (m *bpModule) deepCopy() *bpModule {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000177 return m.transform(deepCopyTransformer)
178}
179
180func (m *bpModule) transform(transformer bpTransformer) *bpModule {
181 transformedModule := transformer.transformModule(m)
182 // Copy the contents of the returned property set into the module and then transform that.
Paul Duffin5b511a22020-01-15 14:23:52 +0000183 transformedModule.bpPropertySet, _ = transformer.transformPropertySet("", transformedModule.bpPropertySet, nil)
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000184 transformedModule.bpPropertySet.transform(transformer)
185 return transformedModule
186}
187
188type deepCopyTransformation struct{}
189
190func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
191 // Take a shallow copy of the module. Any mutable property values will be copied by the
192 // transformer.
193 moduleCopy := *module
194 return &moduleCopy
195}
196
Paul Duffin5b511a22020-01-15 14:23:52 +0000197func (t deepCopyTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000198 // Create a shallow copy of the properties map. Any mutable property values will be copied by the
199 // transformer.
200 propertiesCopy := make(map[string]interface{})
Paul Duffin5b511a22020-01-15 14:23:52 +0000201 for propertyName, value := range propertySet.properties {
202 propertiesCopy[propertyName] = value
203 }
204
205 // Ditto for tags map.
206 tagsCopy := make(map[string]android.BpPropertyTag)
207 for propertyName, propertyTag := range propertySet.tags {
208 tagsCopy[propertyName] = propertyTag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000209 }
210
211 // Create a new property set.
212 return &bpPropertySet{
213 properties: propertiesCopy,
Paul Duffin5b511a22020-01-15 14:23:52 +0000214 tags: tagsCopy,
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000215 order: append([]string(nil), propertySet.order...),
Paul Duffin5b511a22020-01-15 14:23:52 +0000216 }, tag
Paul Duffinb645ec82019-11-27 17:43:54 +0000217}
218
Paul Duffin5b511a22020-01-15 14:23:52 +0000219func (t deepCopyTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000220 // Copy string slice, otherwise return value.
221 if values, ok := value.([]string); ok {
222 valuesCopy := make([]string, len(values))
223 copy(valuesCopy, values)
Paul Duffin5b511a22020-01-15 14:23:52 +0000224 return valuesCopy, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000225 }
Paul Duffin5b511a22020-01-15 14:23:52 +0000226 return value, tag
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000227}
228
229var deepCopyTransformer bpTransformer = deepCopyTransformation{}
230
Paul Duffinb645ec82019-11-27 17:43:54 +0000231// A .bp file
232type bpFile struct {
233 modules map[string]*bpModule
234 order []*bpModule
235}
236
237// Add a module.
238//
239// The module must have had its "name" property set to a string value that
240// is unique within this file.
241func (f *bpFile) AddModule(module android.BpModule) {
242 m := module.(*bpModule)
243 if name, ok := m.getValue("name").(string); ok {
244 if f.modules[name] != nil {
245 panic(fmt.Sprintf("Module %q already exists in bp file", name))
246 }
247
248 f.modules[name] = m
249 f.order = append(f.order, m)
250 } else {
251 panic("Module does not have a name property, or it is not a string")
252 }
253}
254
255func (f *bpFile) newModule(moduleType string) *bpModule {
256 module := &bpModule{
Paul Duffincc72e982020-01-14 15:53:11 +0000257 moduleType: moduleType,
258 bpPropertySet: &bpPropertySet{},
Paul Duffinb645ec82019-11-27 17:43:54 +0000259 }
Paul Duffincc72e982020-01-14 15:53:11 +0000260 module.bpPropertySet.init()
Paul Duffinb645ec82019-11-27 17:43:54 +0000261 return module
262}