diff options
author | 2019-03-04 22:33:56 -0800 | |
---|---|---|
committer | 2019-03-07 18:36:24 +0000 | |
commit | 1b48842a4b83ba6234d26ff4c77a0884f5008f62 (patch) | |
tree | 02cd5ff6fd92a0fbe9de3a5fe34542b75dfbd783 /android/path_properties.go | |
parent | 1361449710eaa5ca4bd0acf01489ae0260d768b6 (diff) |
Add path properties mutator
Add a mutator pass after DepsMutator that visits every property
struct in every module looking for properties that have a tag
`android:"path"`, and automatically add a SourceDepTag dependency
on any module references (":module-name") found. Uses a cache to
store the mapping of property struct type to locations of
properties with the tag.
Test: android/path_properties_test.go
Change-Id: I38c0497843dde4890e9342c3a6f0b402c0720742
Diffstat (limited to 'android/path_properties.go')
-rw-r--r-- | android/path_properties.go | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/android/path_properties.go b/android/path_properties.go new file mode 100644 index 000000000..5d8970927 --- /dev/null +++ b/android/path_properties.go @@ -0,0 +1,123 @@ +// Copyright 2019 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "fmt" + "reflect" + + "github.com/google/blueprint/proptools" +) + +func registerPathDepsMutator(ctx RegisterMutatorsContext) { + ctx.BottomUp("pathdeps", pathDepsMutator).Parallel() +} + +// The pathDepsMutator automatically adds dependencies on any module that is listed with ":module" syntax in a +// property that is tagged with android:"path". +func pathDepsMutator(ctx BottomUpMutatorContext) { + m := ctx.Module().(Module) + if m == nil { + return + } + + props := m.base().customizableProperties + + for _, ps := range props { + pathProperties := pathPropertiesForPropertyStruct(ctx, ps) + pathProperties = FirstUniqueStrings(pathProperties) + + var deps []string + for _, s := range pathProperties { + if m := SrcIsModule(s); m != "" { + deps = append(deps, m) + } + } + + ctx.AddDependency(ctx.Module(), SourceDepTag, deps...) + } +} + +// pathPropertiesForPropertyStruct uses the indexes of properties that are tagged with android:"path" to extract +// all their values from a property struct, returning them as a single slice of strings.. +func pathPropertiesForPropertyStruct(ctx BottomUpMutatorContext, ps interface{}) []string { + v := reflect.ValueOf(ps) + if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { + panic(fmt.Errorf("type %s is not a pointer to a struct", v.Type())) + } + if v.IsNil() { + return nil + } + v = v.Elem() + + pathPropertyIndexes := pathPropertyIndexesForPropertyStruct(ps) + + var ret []string + + for _, i := range pathPropertyIndexes { + sv := fieldByIndex(v, i) + if !sv.IsValid() { + continue + } + + if sv.Kind() == reflect.Ptr { + if sv.IsNil() { + continue + } + sv = sv.Elem() + } + switch sv.Kind() { + case reflect.String: + ret = append(ret, sv.String()) + case reflect.Slice: + ret = append(ret, sv.Interface().([]string)...) + default: + panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`, + v.Type().FieldByIndex(i).Name, v.Type(), sv.Type())) + } + } + + return ret +} + +// fieldByIndex is like reflect.Value.FieldByIndex, but returns an invalid reflect.Value when traversing a nil pointer +// to a struct. +func fieldByIndex(v reflect.Value, index []int) reflect.Value { + if len(index) == 1 { + return v.Field(index[0]) + } + for _, x := range index { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + return reflect.Value{} + } + v = v.Elem() + } + v = v.Field(x) + } + return v +} + +var pathPropertyIndexesCache OncePer + +// pathPropertyIndexesForPropertyStruct returns a list of all of the indexes of properties in property struct type that +// are tagged with android:"path". Each index is a []int suitable for passing to reflect.Value.FieldByIndex. The value +// is cached in a global cache by type. +func pathPropertyIndexesForPropertyStruct(ps interface{}) [][]int { + key := NewCustomOnceKey(reflect.TypeOf(ps)) + return pathPropertyIndexesCache.Once(key, func() interface{} { + return proptools.PropertyIndexesWithTag(ps, "android", "path") + }).([][]int) +} |