1// 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 "reflect" 20 "strings" 21 22 "android/soong/android" 23) 24 25type bpPropertySet struct { 26 properties map[string]interface{} 27 tags map[string]android.BpPropertyTag 28 comments map[string]string 29 order []string 30} 31 32var _ android.BpPropertySet = (*bpPropertySet)(nil) 33 34func (s *bpPropertySet) init() { 35 s.properties = make(map[string]interface{}) 36 s.tags = make(map[string]android.BpPropertyTag) 37} 38 39// 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 101func (s *bpPropertySet) AddProperty(name string, value interface{}) { 102 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 115 if s.properties[name] != nil { 116 panic(fmt.Sprintf("Property %q already exists in property set", name)) 117 } 118 119 s.properties[name] = value 120 s.order = append(s.order, name) 121} 122 123func (s *bpPropertySet) AddPropertyWithTag(name string, value interface{}, tag android.BpPropertyTag) { 124 s.AddProperty(name, value) 125 s.tags[name] = tag 126} 127 128func (s *bpPropertySet) AddPropertySet(name string) android.BpPropertySet { 129 s.AddProperty(name, newPropertySet()) 130 return s.properties[name].(android.BpPropertySet) 131} 132 133func (s *bpPropertySet) getValue(name string) interface{} { 134 return s.properties[name] 135} 136 137func (s *bpPropertySet) getOptionalValue(name string) (interface{}, bool) { 138 value, ok := s.properties[name] 139 return value, ok 140} 141 142func (s *bpPropertySet) getTag(name string) interface{} { 143 return s.tags[name] 144} 145 146func (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 153func (s *bpPropertySet) transformContents(transformer bpPropertyTransformer) { 154 var newOrder []string 155 for _, name := range s.order { 156 value := s.properties[name] 157 tag := s.tags[name] 158 var newValue interface{} 159 var newTag android.BpPropertyTag 160 if propertySet, ok := value.(*bpPropertySet); ok { 161 var newPropertySet *bpPropertySet 162 newPropertySet, newTag = transformPropertySet(transformer, name, propertySet, tag) 163 if newPropertySet == nil { 164 newValue = nil 165 } else { 166 newValue = newPropertySet 167 } 168 } else { 169 newValue, newTag = transformer.transformProperty(name, value, tag) 170 } 171 172 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 178 s.tags[name] = newTag 179 newOrder = append(newOrder, name) 180 } 181 } 182 s.order = newOrder 183} 184 185func transformPropertySet(transformer bpPropertyTransformer, name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) { 186 newPropertySet, newTag := transformer.transformPropertySetBeforeContents(name, propertySet, tag) 187 if newPropertySet != nil { 188 newPropertySet.transformContents(transformer) 189 190 newPropertySet, newTag = transformer.transformPropertySetAfterContents(name, newPropertySet, newTag) 191 } 192 return newPropertySet, newTag 193} 194 195func (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 200 s.tags[name] = nil 201 } 202} 203 204func (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 210func (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 { 234 *bpPropertySet 235 moduleType string 236} 237 238func (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 251var _ android.BpModule = (*bpModule)(nil) 252 253type bpPropertyTransformer interface { 254 // Transform the property set, returning the new property set/tag to insert back into the 255 // 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 // 261 // Returning (nil, ...) will cause the property set to be removed. 262 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) 273 274 // Transform a property, return the new value/tag to insert back into the property set. 275 // 276 // Returning (nil, ...) will cause the property to be removed. 277 transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) 278} 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 301func (t identityTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) { 302 return propertySet, tag 303} 304 305func (t identityTransformation) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) { 306 return propertySet, tag 307} 308 309func (t identityTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) { 310 return value, tag 311} 312 313func (m *bpModule) deepCopy() *bpModule { 314 return m.transform(deepCopyTransformer) 315} 316 317func (m *bpModule) transform(transformer bpTransformer) *bpModule { 318 transformedModule := transformer.transformModule(m) 319 // Copy the contents of the returned property set into the module and then transform that. 320 transformedModule.bpPropertySet, _ = transformPropertySet(transformer, "", transformedModule.bpPropertySet, nil) 321 return transformedModule 322} 323 324type deepCopyTransformation struct { 325 identityTransformation 326} 327 328func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule { 329 // Take a shallow copy of the module. Any mutable property values will be copied by the 330 // transformer. 331 moduleCopy := *module 332 return &moduleCopy 333} 334 335func (t deepCopyTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) { 336 // Create a shallow copy of the properties map. Any mutable property values will be copied by the 337 // transformer. 338 propertiesCopy := make(map[string]interface{}) 339 for propertyName, value := range propertySet.properties { 340 propertiesCopy[propertyName] = value 341 } 342 343 // Ditto for tags map. 344 tagsCopy := make(map[string]android.BpPropertyTag) 345 for propertyName, propertyTag := range propertySet.tags { 346 tagsCopy[propertyName] = propertyTag 347 } 348 349 // Create a new property set. 350 return &bpPropertySet{ 351 properties: propertiesCopy, 352 tags: tagsCopy, 353 order: append([]string(nil), propertySet.order...), 354 }, tag 355} 356 357func (t deepCopyTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) { 358 // Copy string slice, otherwise return value. 359 if values, ok := value.([]string); ok { 360 valuesCopy := make([]string, len(values)) 361 copy(valuesCopy, values) 362 return valuesCopy, tag 363 } 364 return value, tag 365} 366 367var deepCopyTransformer bpTransformer = deepCopyTransformation{} 368 369// A .bp file 370type bpFile struct { 371 modules map[string]*bpModule 372 order []*bpModule 373} 374 375// Add a module. 376// 377// The module must have had its "name" property set to a string value that 378// is unique within this file. 379func (f *bpFile) AddModule(module android.BpModule) { 380 m := module.(*bpModule) 381 moduleType := module.ModuleType() 382 name := m.Name() 383 hasName := true 384 if name == "" { 385 // Use a prefixed module type as the name instead just in case this is something like a package 386 // of namespace module which does not require a name. 387 name = "#" + moduleType 388 hasName = false 389 } 390 391 if f.modules[name] != nil { 392 if hasName { 393 panic(fmt.Sprintf("Module %q already exists in bp file", name)) 394 } else { 395 panic(fmt.Sprintf("Unnamed module type %q already exists in bp file", moduleType)) 396 } 397 } 398 399 f.modules[name] = m 400 f.order = append(f.order, m) 401} 402 403func (f *bpFile) newModule(moduleType string) *bpModule { 404 return newModule(moduleType) 405} 406 407func newModule(moduleType string) *bpModule { 408 module := &bpModule{ 409 moduleType: moduleType, 410 bpPropertySet: newPropertySet(), 411 } 412 return module 413} 414 415func newPropertySet() *bpPropertySet { 416 set := &bpPropertySet{} 417 set.init() 418 return set 419} 420