blob: e0e06f30565d7da9d4f431c9cc12ecf08725d842 [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{}
25 order []string
26}
27
28var _ android.BpPropertySet = (*bpPropertySet)(nil)
29
30func (s *bpPropertySet) init() {
31 s.properties = make(map[string]interface{})
32}
33
34func (s *bpPropertySet) AddProperty(name string, value interface{}) {
35 if s.properties[name] != nil {
36 panic("Property %q already exists in property set")
37 }
38
39 s.properties[name] = value
40 s.order = append(s.order, name)
41}
42
43func (s *bpPropertySet) AddPropertySet(name string) android.BpPropertySet {
44 set := &bpPropertySet{}
45 set.init()
46 s.AddProperty(name, set)
47 return set
48}
49
50func (s *bpPropertySet) getValue(name string) interface{} {
51 return s.properties[name]
52}
53
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000054func (s *bpPropertySet) transform(transformer bpPropertyTransformer) {
55 var newOrder []string
56 for _, name := range s.order {
57 value := s.properties[name]
58 var newValue interface{}
59 if propertySet, ok := value.(*bpPropertySet); ok {
60 newValue = transformer.transformPropertySet(name, propertySet)
Paul Duffincc72e982020-01-14 15:53:11 +000061 } else {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000062 newValue = transformer.transformProperty(name, value)
Paul Duffincc72e982020-01-14 15:53:11 +000063 }
Paul Duffinb645ec82019-11-27 17:43:54 +000064
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000065 if newValue == nil {
66 // Delete the property from the map and exclude it from the new order.
67 delete(s.properties, name)
68 } else {
69 // Update the property in the map and add the name to the new order list.
70 s.properties[name] = newValue
71 newOrder = append(newOrder, name)
72 }
Paul Duffinb645ec82019-11-27 17:43:54 +000073 }
Paul Duffinb4d9c1f2020-01-15 11:52:11 +000074 s.order = newOrder
Paul Duffinb645ec82019-11-27 17:43:54 +000075}
76
77func (s *bpPropertySet) setProperty(name string, value interface{}) {
78 if s.properties[name] == nil {
79 s.AddProperty(name, value)
80 } else {
81 s.properties[name] = value
82 }
83}
84
85func (s *bpPropertySet) insertAfter(position string, name string, value interface{}) {
86 if s.properties[name] != nil {
87 panic("Property %q already exists in property set")
88 }
89
90 // Add the name to the end of the order, to ensure it has necessary capacity
91 // and to handle the case when the position does not exist.
92 s.order = append(s.order, name)
93
94 // Search through the order for the item that matches supplied position. If
95 // found then insert the name of the new property after it.
96 for i, v := range s.order {
97 if v == position {
98 // Copy the items after the one where the new property should be inserted.
99 copy(s.order[i+2:], s.order[i+1:])
100 // Insert the item in the list.
101 s.order[i+1] = name
102 }
103 }
104
105 s.properties[name] = value
106}
107
108type bpModule struct {
Paul Duffincc72e982020-01-14 15:53:11 +0000109 *bpPropertySet
Paul Duffinb645ec82019-11-27 17:43:54 +0000110 moduleType string
111}
112
113var _ android.BpModule = (*bpModule)(nil)
114
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000115type bpPropertyTransformer interface {
116 // Transform the property set, returning the new property set to insert back into the
117 // parent property set (or module if this is the top level property set).
118 //
119 // This will be called before transforming the properties in the supplied set.
120 //
121 // The name will be "" for the top level property set.
122 //
123 // Returning nil will cause the property set to be removed.
124 transformPropertySet(name string, propertySet *bpPropertySet) *bpPropertySet
125
126 // Transform a property, return the new value to insert back into the property set.
127 //
128 // Returning nil will cause the property to be removed.
129 transformProperty(name string, value interface{}) interface{}
130}
131
132// Interface for transforming bpModule objects.
133type bpTransformer interface {
134 // Transform the module, returning the result.
135 //
136 // The method can either create a new module and return that, or modify the supplied module
137 // in place and return that.
138 //
139 // After this returns the transformer is applied to the contents of the returned module.
140 transformModule(module *bpModule) *bpModule
141
142 bpPropertyTransformer
143}
144
145type identityTransformation struct{}
146
147var _ bpTransformer = (*identityTransformation)(nil)
148
149func (t identityTransformation) transformModule(module *bpModule) *bpModule {
150 return module
151}
152
153func (t identityTransformation) transformPropertySet(name string, propertySet *bpPropertySet) *bpPropertySet {
154 return propertySet
155}
156
157func (t identityTransformation) transformProperty(name string, value interface{}) interface{} {
158 return value
159}
160
Paul Duffincc72e982020-01-14 15:53:11 +0000161func (m *bpModule) deepCopy() *bpModule {
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000162 return m.transform(deepCopyTransformer)
163}
164
165func (m *bpModule) transform(transformer bpTransformer) *bpModule {
166 transformedModule := transformer.transformModule(m)
167 // Copy the contents of the returned property set into the module and then transform that.
168 transformedModule.bpPropertySet = transformer.transformPropertySet("", transformedModule.bpPropertySet)
169 transformedModule.bpPropertySet.transform(transformer)
170 return transformedModule
171}
172
173type deepCopyTransformation struct{}
174
175func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
176 // Take a shallow copy of the module. Any mutable property values will be copied by the
177 // transformer.
178 moduleCopy := *module
179 return &moduleCopy
180}
181
182func (t deepCopyTransformation) transformPropertySet(name string, propertySet *bpPropertySet) *bpPropertySet {
183 // Create a shallow copy of the properties map. Any mutable property values will be copied by the
184 // transformer.
185 propertiesCopy := make(map[string]interface{})
186 for p, v := range propertySet.properties {
187 propertiesCopy[p] = v
188 }
189
190 // Create a new property set.
191 return &bpPropertySet{
192 properties: propertiesCopy,
193 order: append([]string(nil), propertySet.order...),
Paul Duffinb645ec82019-11-27 17:43:54 +0000194 }
195}
196
Paul Duffinb4d9c1f2020-01-15 11:52:11 +0000197func (t deepCopyTransformation) transformProperty(name string, value interface{}) interface{} {
198 // Copy string slice, otherwise return value.
199 if values, ok := value.([]string); ok {
200 valuesCopy := make([]string, len(values))
201 copy(valuesCopy, values)
202 return valuesCopy
203 }
204 return value
205}
206
207var deepCopyTransformer bpTransformer = deepCopyTransformation{}
208
Paul Duffinb645ec82019-11-27 17:43:54 +0000209// A .bp file
210type bpFile struct {
211 modules map[string]*bpModule
212 order []*bpModule
213}
214
215// Add a module.
216//
217// The module must have had its "name" property set to a string value that
218// is unique within this file.
219func (f *bpFile) AddModule(module android.BpModule) {
220 m := module.(*bpModule)
221 if name, ok := m.getValue("name").(string); ok {
222 if f.modules[name] != nil {
223 panic(fmt.Sprintf("Module %q already exists in bp file", name))
224 }
225
226 f.modules[name] = m
227 f.order = append(f.order, m)
228 } else {
229 panic("Module does not have a name property, or it is not a string")
230 }
231}
232
233func (f *bpFile) newModule(moduleType string) *bpModule {
234 module := &bpModule{
Paul Duffincc72e982020-01-14 15:53:11 +0000235 moduleType: moduleType,
236 bpPropertySet: &bpPropertySet{},
Paul Duffinb645ec82019-11-27 17:43:54 +0000237 }
Paul Duffincc72e982020-01-14 15:53:11 +0000238 module.bpPropertySet.init()
Paul Duffinb645ec82019-11-27 17:43:54 +0000239 return module
240}