Add android:replace_instead_of_append am: 2437d5edb9
Original change: https://android-review.googlesource.com/c/platform/build/blueprint/+/3025378 Change-Id: I0af8eab5aa136b05c0a97acdbe40380eccfd7f2d Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
e8602b8b22
3 changed files with 59 additions and 25 deletions
|
@ -79,7 +79,8 @@ var _ configurableMarker = Configurable[string]{}.marker
|
|||
// appendWrapper exists so that we can set the value of append
|
||||
// from a non-pointer method receiver. (setAppend)
|
||||
type appendWrapper[T ConfigurableElements] struct {
|
||||
append Configurable[T]
|
||||
append Configurable[T]
|
||||
replace bool
|
||||
}
|
||||
|
||||
func (c *Configurable[T]) GetType() parser.SelectType {
|
||||
|
@ -96,12 +97,17 @@ func (c *Configurable[T]) Evaluate(evaluator ConfigurableEvaluator) *T {
|
|||
if c == nil || c.appendWrapper == nil {
|
||||
return nil
|
||||
}
|
||||
return mergeConfiguredValues(
|
||||
c.evaluateNonTransitive(evaluator),
|
||||
c.appendWrapper.append.Evaluate(evaluator),
|
||||
c.propertyName,
|
||||
evaluator,
|
||||
)
|
||||
if c.appendWrapper.replace {
|
||||
return replaceConfiguredValues(
|
||||
c.evaluateNonTransitive(evaluator),
|
||||
c.appendWrapper.append.Evaluate(evaluator),
|
||||
)
|
||||
} else {
|
||||
return appendConfiguredValues(
|
||||
c.evaluateNonTransitive(evaluator),
|
||||
c.appendWrapper.append.Evaluate(evaluator),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Configurable[T]) evaluateNonTransitive(evaluator ConfigurableEvaluator) *T {
|
||||
|
@ -142,7 +148,7 @@ func (c *Configurable[T]) evaluateNonTransitive(evaluator ConfigurableEvaluator)
|
|||
return nil
|
||||
}
|
||||
|
||||
func mergeConfiguredValues[T ConfigurableElements](a, b *T, propertyName string, evalutor ConfigurableEvaluator) *T {
|
||||
func appendConfiguredValues[T ConfigurableElements](a, b *T) *T {
|
||||
if a == nil && b == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -188,12 +194,19 @@ func mergeConfiguredValues[T ConfigurableElements](a, b *T, propertyName string,
|
|||
}
|
||||
}
|
||||
|
||||
func replaceConfiguredValues[T ConfigurableElements](a, b *T) *T {
|
||||
if b != nil {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// configurableReflection is an interface that exposes some methods that are
|
||||
// helpful when working with reflect.Values of Configurable objects, used by
|
||||
// the property unpacking code. You can't call unexported methods from reflection,
|
||||
// (at least without unsafe pointer trickery) so this is the next best thing.
|
||||
type configurableReflection interface {
|
||||
setAppend(append any)
|
||||
setAppend(append any, replace bool)
|
||||
configuredType() reflect.Type
|
||||
cloneToReflectValuePtr() reflect.Value
|
||||
isEmpty() bool
|
||||
|
@ -216,11 +229,12 @@ func (c *Configurable[T]) initialize(propertyName string, typ parser.SelectType,
|
|||
c.appendWrapper = &appendWrapper[T]{}
|
||||
}
|
||||
|
||||
func (c Configurable[T]) setAppend(append any) {
|
||||
func (c Configurable[T]) setAppend(append any, replace bool) {
|
||||
if c.appendWrapper.append.isEmpty() {
|
||||
c.appendWrapper.append = append.(Configurable[T])
|
||||
c.appendWrapper.replace = replace
|
||||
} else {
|
||||
c.appendWrapper.append.setAppend(append)
|
||||
c.appendWrapper.append.setAppend(append, replace)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,6 +262,7 @@ func (c *Configurable[T]) clone() *Configurable[T] {
|
|||
inner = &appendWrapper[T]{}
|
||||
if !c.appendWrapper.append.isEmpty() {
|
||||
inner.append = *c.appendWrapper.append.clone()
|
||||
inner.replace = c.appendWrapper.replace
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -154,9 +154,18 @@ func ExtendMatchingProperties(dst []interface{}, src interface{},
|
|||
type Order int
|
||||
|
||||
const (
|
||||
// When merging properties, strings and lists will be concatenated, and booleans will be OR'd together
|
||||
Append Order = iota
|
||||
// Same as append, but acts as if the arguments to the extend* functions were swapped. The src value will be
|
||||
// prepended to the dst value instead of appended.
|
||||
Prepend
|
||||
// Instead of concatenating/ORing properties, the dst value will be completely replaced by the src value.
|
||||
// Replace currently only works for slices, maps, and configurable properties. Due to legacy behavior,
|
||||
// pointer properties will always act as if they're using replace ordering.
|
||||
Replace
|
||||
// Same as replace, but acts as if the arguments to the extend* functions were swapped. The src value will be
|
||||
// used only if the dst value was unset.
|
||||
Prepend_replace
|
||||
)
|
||||
|
||||
type ExtendPropertyFilterFunc func(dstField, srcField reflect.StructField) (bool, error)
|
||||
|
@ -420,6 +429,14 @@ func extendPropertiesRecursive(dstValues []reflect.Value, srcValue reflect.Value
|
|||
}
|
||||
}
|
||||
|
||||
if HasTag(dstField, "android", "replace_instead_of_append") {
|
||||
if order == Append {
|
||||
order = Replace
|
||||
} else if order == Prepend {
|
||||
order = Prepend_replace
|
||||
}
|
||||
}
|
||||
|
||||
ExtendBasicType(dstFieldValue, srcFieldValue, order)
|
||||
}
|
||||
|
||||
|
@ -438,7 +455,7 @@ func extendPropertiesRecursive(dstValues []reflect.Value, srcValue reflect.Value
|
|||
}
|
||||
|
||||
func ExtendBasicType(dstFieldValue, srcFieldValue reflect.Value, order Order) {
|
||||
prepend := order == Prepend
|
||||
prepend := order == Prepend || order == Prepend_replace
|
||||
|
||||
switch srcFieldValue.Kind() {
|
||||
case reflect.Struct:
|
||||
|
@ -447,11 +464,18 @@ func ExtendBasicType(dstFieldValue, srcFieldValue reflect.Value, order Order) {
|
|||
}
|
||||
if dstFieldValue.Interface().(configurableReflection).isEmpty() {
|
||||
dstFieldValue.Set(srcFieldValue)
|
||||
} else if prepend {
|
||||
srcFieldValue.Interface().(configurableReflection).setAppend(dstFieldValue.Interface())
|
||||
} else if order == Prepend {
|
||||
srcFieldValue.Interface().(configurableReflection).setAppend(dstFieldValue.Interface(), false)
|
||||
dstFieldValue.Set(srcFieldValue)
|
||||
} else if order == Append {
|
||||
dstFieldValue.Interface().(configurableReflection).setAppend(srcFieldValue.Interface(), false)
|
||||
} else if order == Replace {
|
||||
dstFieldValue.Interface().(configurableReflection).setAppend(srcFieldValue.Interface(), true)
|
||||
} else if order == Prepend_replace {
|
||||
srcFieldValue.Interface().(configurableReflection).setAppend(dstFieldValue.Interface(), true)
|
||||
dstFieldValue.Set(srcFieldValue)
|
||||
} else {
|
||||
dstFieldValue.Interface().(configurableReflection).setAppend(srcFieldValue.Interface())
|
||||
panic(fmt.Sprintf("Unexpected order: %d", order))
|
||||
}
|
||||
case reflect.Bool:
|
||||
// Boolean OR
|
||||
|
@ -550,14 +574,9 @@ func ExtendBasicType(dstFieldValue, srcFieldValue reflect.Value, order Order) {
|
|||
if !isConfigurable(srcFieldValue.Type()) {
|
||||
panic("Should be unreachable")
|
||||
}
|
||||
if dstFieldValue.Interface().(configurableReflection).isEmpty() {
|
||||
dstFieldValue.Set(srcFieldValue)
|
||||
} else if prepend {
|
||||
srcFieldValue.Interface().(configurableReflection).setAppend(dstFieldValue.Interface())
|
||||
dstFieldValue.Set(srcFieldValue)
|
||||
} else {
|
||||
dstFieldValue.Interface().(configurableReflection).setAppend(srcFieldValue.Interface())
|
||||
}
|
||||
panic("Don't use pointers to Configurable properties. All Configurable properties can be unset, " +
|
||||
"and the 'replacing' behavior can be accomplished with the `blueprint:\"replace_instead_of_append\" " +
|
||||
"struct field tag. There's no reason to have a pointer configurable property.")
|
||||
default:
|
||||
panic(fmt.Errorf("unexpected pointer kind %s", ptrKind))
|
||||
}
|
||||
|
|
|
@ -307,7 +307,7 @@ func (ctx *unpackContext) unpackToStruct(namePrefix string, structValue reflect.
|
|||
configurableType := fieldValue.Type()
|
||||
configuredType := fieldValue.Interface().(configurableReflection).configuredType()
|
||||
if unpackedValue, ok := ctx.unpackToConfigurable(propertyName, property, configurableType, configuredType); ok {
|
||||
ExtendBasicType(fieldValue, unpackedValue, Append)
|
||||
ExtendBasicType(fieldValue, unpackedValue.Elem(), Append)
|
||||
}
|
||||
if len(ctx.errs) >= maxUnpackErrors {
|
||||
return
|
||||
|
@ -476,7 +476,7 @@ func (ctx *unpackContext) unpackToConfigurable(propertyName string, property *pa
|
|||
if !ok {
|
||||
return reflect.New(configurableType), false
|
||||
}
|
||||
result.Interface().(configurableReflection).setAppend(val.Elem().Interface())
|
||||
result.Interface().(configurableReflection).setAppend(val.Elem().Interface(), false)
|
||||
}
|
||||
return resultPtr, true
|
||||
default:
|
||||
|
|
Loading…
Reference in a new issue