Add support for setting string property in bpmodify

Add a -str argument to set a property to a string value.

Bug: 186723288
Test: bpmodify_test.go
Change-Id: I490e3be182693c8720020814da579e6e788b3d9f
This commit is contained in:
Colin Cross 2021-04-29 20:16:40 -07:00
parent 5ef7b6608c
commit b1abbada6a
2 changed files with 100 additions and 28 deletions

View file

@ -30,6 +30,8 @@ var (
targetedProperty = new(qualifiedProperty) targetedProperty = new(qualifiedProperty)
addIdents = new(identSet) addIdents = new(identSet)
removeIdents = new(identSet) removeIdents = new(identSet)
setString *string
) )
func init() { func init() {
@ -38,6 +40,7 @@ func init() {
flag.Var(targetedProperty, "property", "fully qualified `name` of property to modify (default \"deps\")") flag.Var(targetedProperty, "property", "fully qualified `name` of property to modify (default \"deps\")")
flag.Var(addIdents, "a", "comma or whitespace separated list of identifiers to add") flag.Var(addIdents, "a", "comma or whitespace separated list of identifiers to add")
flag.Var(removeIdents, "r", "comma or whitespace separated list of identifiers to remove") flag.Var(removeIdents, "r", "comma or whitespace separated list of identifiers to remove")
flag.Var(stringPtrFlag{&setString}, "str", "set a string property")
flag.Usage = usage flag.Usage = usage
} }
@ -147,14 +150,18 @@ func processModule(module *parser.Module, moduleName string,
return false, []error{err} return false, []error{err}
} }
if prop == nil { if prop == nil {
if len(addIdents.idents) == 0 { if len(addIdents.idents) > 0 {
// We are adding something to a non-existing list prop, so we need to create it first.
prop, modified, err = createRecursiveProperty(module, targetedProperty.name(), targetedProperty.prefixes(), &parser.List{})
} else if setString != nil {
// We setting a non-existent string property, so we need to create it first.
prop, modified, err = createRecursiveProperty(module, targetedProperty.name(), targetedProperty.prefixes(), &parser.String{})
} else {
// We cannot find an existing prop, and we aren't adding anything to the prop, // We cannot find an existing prop, and we aren't adding anything to the prop,
// which means we must be removing something from a non-existing prop, // which means we must be removing something from a non-existing prop,
// which means this is a noop. // which means this is a noop.
return false, nil return false, nil
} }
// Else we are adding something to a non-existing prop, so we need to create it first.
prop, modified, err = createRecursiveProperty(module, targetedProperty.name(), targetedProperty.prefixes())
if err != nil { if err != nil {
// Here should be unreachable, but still handle it for completeness. // Here should be unreachable, but still handle it for completeness.
return false, []error{err} return false, []error{err}
@ -166,16 +173,18 @@ func processModule(module *parser.Module, moduleName string,
} }
func getRecursiveProperty(module *parser.Module, name string, prefixes []string) (prop *parser.Property, err error) { func getRecursiveProperty(module *parser.Module, name string, prefixes []string) (prop *parser.Property, err error) {
prop, _, err = getOrCreateRecursiveProperty(module, name, prefixes, false) prop, _, err = getOrCreateRecursiveProperty(module, name, prefixes, nil)
return prop, err return prop, err
} }
func createRecursiveProperty(module *parser.Module, name string, prefixes []string) (prop *parser.Property, modified bool, err error) { func createRecursiveProperty(module *parser.Module, name string, prefixes []string,
return getOrCreateRecursiveProperty(module, name, prefixes, true) empty parser.Expression) (prop *parser.Property, modified bool, err error) {
return getOrCreateRecursiveProperty(module, name, prefixes, empty)
} }
func getOrCreateRecursiveProperty(module *parser.Module, name string, prefixes []string, func getOrCreateRecursiveProperty(module *parser.Module, name string, prefixes []string,
createIfNotFound bool) (prop *parser.Property, modified bool, err error) { empty parser.Expression) (prop *parser.Property, modified bool, err error) {
m := &module.Map m := &module.Map
for i, prefix := range prefixes { for i, prefix := range prefixes {
if prop, found := m.GetProperty(prefix); found { if prop, found := m.GetProperty(prefix); found {
@ -187,7 +196,7 @@ func getOrCreateRecursiveProperty(module *parser.Module, name string, prefixes [
return nil, false, fmt.Errorf("Expected property %q to be a map, found %s", return nil, false, fmt.Errorf("Expected property %q to be a map, found %s",
strings.Join(prefixes[:i+1], "."), prop.Value.Type()) strings.Join(prefixes[:i+1], "."), prop.Value.Type())
} }
} else if createIfNotFound { } else if empty != nil {
mm := &parser.Map{} mm := &parser.Map{}
m.Properties = append(m.Properties, &parser.Property{Name: prefix, Value: mm}) m.Properties = append(m.Properties, &parser.Property{Name: prefix, Value: mm})
m = mm m = mm
@ -201,8 +210,8 @@ func getOrCreateRecursiveProperty(module *parser.Module, name string, prefixes [
if prop, found := m.GetProperty(name); found { if prop, found := m.GetProperty(name); found {
// We've found a property in the AST, which must mean we didn't modify the AST. // We've found a property in the AST, which must mean we didn't modify the AST.
return prop, false, nil return prop, false, nil
} else if createIfNotFound { } else if empty != nil {
prop = &parser.Property{Name: name, Value: &parser.List{}} prop = &parser.Property{Name: name, Value: empty}
m.Properties = append(m.Properties, prop) m.Properties = append(m.Properties, prop)
return prop, true, nil return prop, true, nil
} else { } else {
@ -222,26 +231,37 @@ func processParameter(value parser.Expression, paramName, moduleName string,
paramName, moduleName)} paramName, moduleName)}
} }
list, ok := value.(*parser.List) if len(addIdents.idents) > 0 || len(removeIdents.idents) > 0 {
if !ok { list, ok := value.(*parser.List)
return false, []error{fmt.Errorf("expected parameter %s in module %s to be list, found %s", if !ok {
paramName, moduleName, value.Type().String())} return false, []error{fmt.Errorf("expected parameter %s in module %s to be list, found %s",
} paramName, moduleName, value.Type().String())}
}
wasSorted := parser.ListIsSorted(list) wasSorted := parser.ListIsSorted(list)
for _, a := range addIdents.idents { for _, a := range addIdents.idents {
m := parser.AddStringToList(list, a) m := parser.AddStringToList(list, a)
modified = modified || m modified = modified || m
} }
for _, r := range removeIdents.idents { for _, r := range removeIdents.idents {
m := parser.RemoveStringFromList(list, r) m := parser.RemoveStringFromList(list, r)
modified = modified || m modified = modified || m
} }
if (wasSorted || *sortLists) && modified { if (wasSorted || *sortLists) && modified {
parser.SortList(file, list) parser.SortList(file, list)
}
} else if setString != nil {
str, ok := value.(*parser.String)
if !ok {
return false, []error{fmt.Errorf("expected parameter %s in module %s to be string, found %s",
paramName, moduleName, value.Type().String())}
}
str.Value = *setString
modified = true
} }
return modified, nil return modified, nil
@ -304,8 +324,8 @@ func main() {
return return
} }
if len(addIdents.idents) == 0 && len(removeIdents.idents) == 0 { if len(addIdents.idents) == 0 && len(removeIdents.idents) == 0 && setString == nil {
report(fmt.Errorf("-a or -r parameter is required")) report(fmt.Errorf("-a, -r or -str parameter is required"))
return return
} }
@ -352,6 +372,22 @@ func diff(b1, b2 []byte) (data []byte, err error) {
} }
type stringPtrFlag struct {
s **string
}
func (f stringPtrFlag) Set(s string) error {
*f.s = &s
return nil
}
func (f stringPtrFlag) String() string {
if f.s == nil || *f.s == nil {
return ""
}
return **f.s
}
type identSet struct { type identSet struct {
idents []string idents []string
all bool all bool

View file

@ -19,6 +19,7 @@ import (
"testing" "testing"
"github.com/google/blueprint/parser" "github.com/google/blueprint/parser"
"github.com/google/blueprint/proptools"
) )
var testCases = []struct { var testCases = []struct {
@ -28,6 +29,7 @@ var testCases = []struct {
property string property string
addSet string addSet string
removeSet string removeSet string
setString *string
}{ }{
{ {
name: "add", name: "add",
@ -249,6 +251,39 @@ var testCases = []struct {
property: "deps", property: "deps",
addSet: "bar-v10-bar", addSet: "bar-v10-bar",
}, },
{
name: "set string",
input: `
cc_foo {
name: "foo",
}
`,
output: `
cc_foo {
name: "foo",
foo: "bar",
}
`,
property: "foo",
setString: proptools.StringPtr("bar"),
},
{
name: "set existing string",
input: `
cc_foo {
name: "foo",
foo: "baz",
}
`,
output: `
cc_foo {
name: "foo",
foo: "bar",
}
`,
property: "foo",
setString: proptools.StringPtr("bar"),
},
} }
func simplifyModuleDefinition(def string) string { func simplifyModuleDefinition(def string) string {
@ -265,6 +300,7 @@ func TestProcessModule(t *testing.T) {
targetedProperty.Set(testCase.property) targetedProperty.Set(testCase.property)
addIdents.Set(testCase.addSet) addIdents.Set(testCase.addSet)
removeIdents.Set(testCase.removeSet) removeIdents.Set(testCase.removeSet)
setString = testCase.setString
inAst, errs := parser.ParseAndEval("", strings.NewReader(testCase.input), parser.NewScope(nil)) inAst, errs := parser.ParseAndEval("", strings.NewReader(testCase.input), parser.NewScope(nil))
if len(errs) > 0 { if len(errs) > 0 {