Skip to content

Commit

Permalink
extract to maps, use viper fork
Browse files Browse the repository at this point in the history
  • Loading branch information
EronWright committed Feb 13, 2024
1 parent 76bb7bd commit f17e389
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 7 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,5 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/frand v1.4.2 // indirect
)

replace github.com/mitchellh/mapstructure => github.com/go-viper/mapstructure v1.6.0
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgF
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
github.com/go-viper/mapstructure v1.6.0 h1:0WdPOF2rmmQDN1xo8qIgxyugvLp71HrZSWyGLxofobw=
github.com/go-viper/mapstructure v1.6.0/go.mod h1:FcbLReH7/cjaC0RVQR+LHFIrBhHF3s1e/ud1KMDoBVw=
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
Expand Down Expand Up @@ -111,8 +113,6 @@ github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
Expand Down
32 changes: 27 additions & 5 deletions resourcex/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
package resourcex

import (
"fmt"
"regexp"
"strconv"

"github.com/mitchellh/mapstructure"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
Expand Down Expand Up @@ -81,10 +82,7 @@ func Extract(target interface{}, props resource.PropertyMap, opts ExtractOptions
// visit extracts summary information about the given property paths.
func (r *ExtractResult) visit(props resource.PropertyValue, paths []string) error {
for _, path := range paths {
p, err := resource.ParsePropertyPath(path)
if err != nil {
return fmt.Errorf("parse error for path %q: %v", path, err)
}
p := parsePath(path)
visitor := func(v resource.PropertyValue) {
switch {
case v.IsComputed():
Expand Down Expand Up @@ -120,3 +118,27 @@ func mergeDependencies(slice []resource.URN, elems ...resource.URN) []resource.U
}
return slice
}

var (
// matches a path component of the form: "^x", ".x", "[0]", "[*]", "[x]"
pathRegexp = regexp.MustCompile(`(?:(?:(?:^|[.])(?P<key>[A-Za-z0-9_-]+))|(?:\[(?P<index>\d+|\*|[A-Za-z0-9_.-]+)\]))`)
)

// parsePath parses a property path as produced by the mapstructure decoder.
func parsePath(path string) resource.PropertyPath {
result := resource.PropertyPath{}
for _, match := range pathRegexp.FindAllStringSubmatch(path, -1) {
key := match[pathRegexp.SubexpIndex("key")]
index := match[pathRegexp.SubexpIndex("index")]
if key != "" {
result = append(result, key)
} else if index == "*" {
result = append(result, "*")
} else if i, err := strconv.Atoi(index); err == nil {
result = append(result, i)
} else {
result = append(result, index)
}
}
return result
}
104 changes: 104 additions & 0 deletions resourcex/extract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,43 @@ func Test_Extract(t *testing.T) {
result: ExtractResult{ContainsSecrets: false, ContainsUnknowns: false},
actual: Required{},
},
{
name: "Map_Null",
props: resource.PropertyMap{
"null": resource.NewNullProperty(),
},
expected: map[string]any{
"null": nil,
},
result: ExtractResult{ContainsSecrets: false, ContainsUnknowns: false},
actual: map[string]any{},
},
{
name: "Map_Computed",
props: resource.PropertyMap{
"computed": resource.MakeComputed(resource.NewStringProperty("")),
},
expected: map[string]any{
"computed": nil,
},
result: ExtractResult{ContainsSecrets: false, ContainsUnknowns: false}, // limitation: no secretness
actual: map[string]any{},
},
{
name: "Map_Object",
props: resource.PropertyMap{
"object": resource.NewObjectProperty(resource.PropertyMap{
"string": resource.MakeSecret(resource.NewStringProperty("string")),
}),
},
expected: map[string]any{
"object": map[string]any{
"string": "string",
},
},
result: ExtractResult{ContainsSecrets: false, ContainsUnknowns: false}, // limitation: no unknownness
actual: map[string]any{},
},
{
name: "Ignored_Computed",
props: resource.PropertyMap{
Expand Down Expand Up @@ -490,6 +527,9 @@ func Test_Extract(t *testing.T) {
}
for _, tt := range tests {
tt := tt
if tt.name != "Map_Object" {
continue
}
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
result, err := Extract(&tt.actual, tt.props, tt.opts)
Expand Down Expand Up @@ -634,3 +674,67 @@ func printJSON(v interface{}) string {
}
return string(val)
}

func Test_parsePath(t *testing.T) {
t.Parallel()

tests := []struct {
// name string
path string
expected resource.PropertyPath
err error
}{
{
path: "x",
expected: resource.PropertyPath{"x"},
},
{
path: "x.y",
expected: resource.PropertyPath{"x", "y"},
},
{
path: "x.y.z",
expected: resource.PropertyPath{"x", "y", "z"},
},
{
path: "[0]",
expected: resource.PropertyPath{0},
},
{
path: "x[0]",
expected: resource.PropertyPath{"x", 0},
},
{
path: "x[*]",
expected: resource.PropertyPath{"x", "*"},
},
{
path: "x[y]",
expected: resource.PropertyPath{"x", "y"},
},
{
path: "x[y.z]",
expected: resource.PropertyPath{"x", "y.z"},
},
{
path: "x[0].z",
expected: resource.PropertyPath{"x", 0, "z"},
},
{
path: "x[0][y][z]",
expected: resource.PropertyPath{"x", 0, "y", "z"},
},
{
path: "x[0][1].z",
expected: resource.PropertyPath{"x", 0, 1, "z"},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.path, func(t *testing.T) {
t.Parallel()
actual := parsePath(tt.path)
require.Equal(t, tt.expected, actual, "expected path")
})
}
}

0 comments on commit f17e389

Please sign in to comment.