Skip to content

Commit ef94e28

Browse files
Move property path code to separate file (#2497)
This is a pure refactor and just moves the propertyPath-related code to a new file. This is a separate PR to make reviewing easier. Stacked on #2515, #2516 and #2496
1 parent 2cdff49 commit ef94e28

File tree

2 files changed

+108
-102
lines changed

2 files changed

+108
-102
lines changed

pkg/tfbridge/detailed_diff.go

Lines changed: 1 addition & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ import (
99
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
1010
pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go"
1111

12-
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/info"
1312
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
1413
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/walk"
15-
"github.com/pulumi/pulumi-terraform-bridge/v3/unstable/propertyvalue"
1614
)
1715

1816
func isPresent(val resource.PropertyValue) bool {
@@ -21,11 +19,6 @@ func isPresent(val resource.PropertyValue) bool {
2119
!(val.IsObject() && val.ObjectValue() == nil)
2220
}
2321

24-
func isForceNew(tfs shim.Schema, ps *SchemaInfo) bool {
25-
return (tfs != nil && tfs.ForceNew()) ||
26-
(ps != nil && ps.ForceNew != nil && *ps.ForceNew)
27-
}
28-
2922
func sortedMergedKeys[K cmp.Ordered, V any, M ~map[K]V](a, b M) []K {
3023
keys := make(map[K]struct{})
3124
for k := range a {
@@ -62,67 +55,6 @@ func isTypeShapeMismatched(val resource.PropertyValue, propType shim.ValueType)
6255
}
6356
}
6457

65-
func lookupSchemas(
66-
path propertyPath, tfs shim.SchemaMap, ps map[string]*info.Schema,
67-
) (shim.Schema, *info.Schema, error) {
68-
schemaPath := PropertyPathToSchemaPath(resource.PropertyPath(path), tfs, ps)
69-
return LookupSchemas(schemaPath, tfs, ps)
70-
}
71-
72-
func propertyPathTriggersReplacement(
73-
path propertyPath, rootTFSchema shim.SchemaMap, rootPulumiSchema map[string]*info.Schema,
74-
) bool {
75-
// A change on a property might trigger a replacement if:
76-
// - The property itself is marked as ForceNew
77-
// - The direct parent property is a collection (list, set, map) and is marked as ForceNew
78-
// See pkg/cross-tests/diff_cross_test.go
79-
// TestAttributeCollectionForceNew, TestBlockCollectionForceNew, TestBlockCollectionElementForceNew
80-
// for a full case study of replacements in TF
81-
tfs, ps, err := lookupSchemas(path, rootTFSchema, rootPulumiSchema)
82-
if err != nil {
83-
return false
84-
}
85-
if isForceNew(tfs, ps) {
86-
return true
87-
}
88-
89-
if len(path) == 1 {
90-
return false
91-
}
92-
93-
parent := path[:len(path)-1]
94-
tfs, ps, err = lookupSchemas(parent, rootTFSchema, rootPulumiSchema)
95-
if err != nil {
96-
return false
97-
}
98-
// Note this is mimicking the TF behaviour, so the effective type is not considered here.
99-
if tfs.Type() != shim.TypeList && tfs.Type() != shim.TypeSet && tfs.Type() != shim.TypeMap {
100-
return false
101-
}
102-
return isForceNew(tfs, ps)
103-
}
104-
105-
func propertyValueTriggersReplacement(
106-
path propertyPath, value resource.PropertyValue, tfs shim.SchemaMap, ps map[string]*info.Schema,
107-
) bool {
108-
replacement := false
109-
visitor := func(subpath resource.PropertyPath, val resource.PropertyValue) (resource.PropertyValue, error) {
110-
if propertyPathTriggersReplacement(propertyPath(subpath), tfs, ps) {
111-
replacement = true
112-
}
113-
return val, nil
114-
}
115-
116-
_, err := propertyvalue.TransformPropertyValue(
117-
resource.PropertyPath(path),
118-
visitor,
119-
value,
120-
)
121-
contract.AssertNoErrorf(err, "TransformPropertyValue should not return an error")
122-
123-
return replacement
124-
}
125-
12658
func promoteToReplace(diff *pulumirpc.PropertyDiff) *pulumirpc.PropertyDiff {
12759
if diff == nil {
12860
return nil
@@ -191,39 +123,7 @@ func makeBaseDiff(old, new resource.PropertyValue) baseDiff {
191123
return undecidedDiff
192124
}
193125

194-
type (
195-
detailedDiffKey string
196-
propertyPath resource.PropertyPath
197-
)
198-
199-
func newPropertyPath(root resource.PropertyKey) propertyPath {
200-
return propertyPath{string(root)}
201-
}
202-
203-
func (k propertyPath) String() string {
204-
return resource.PropertyPath(k).String()
205-
}
206-
207-
func (k propertyPath) Key() detailedDiffKey {
208-
return detailedDiffKey(k.String())
209-
}
210-
211-
func (k propertyPath) append(subkey interface{}) propertyPath {
212-
return append(k, subkey)
213-
}
214-
215-
func (k propertyPath) Subpath(subkey string) propertyPath {
216-
return k.append(subkey)
217-
}
218-
219-
func (k propertyPath) Index(i int) propertyPath {
220-
return k.append(i)
221-
}
222-
223-
func (k propertyPath) IsReservedKey() bool {
224-
leaf := k[len(k)-1]
225-
return leaf == "__meta" || leaf == "__defaults"
226-
}
126+
type detailedDiffKey string
227127

228128
type detailedDiffer struct {
229129
tfs shim.SchemaMap
@@ -310,7 +210,6 @@ func (differ detailedDiffer) makePropDiff(
310210
return nil
311211
}
312212
propType := differ.getEffectiveType(differ.propertyPathToSchemaPath(path))
313-
314213
if isTypeShapeMismatched(old, propType) || isTypeShapeMismatched(new, propType) {
315214
return differ.makePlainPropDiff(path, old, new)
316215
}

pkg/tfbridge/property_path.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package tfbridge
2+
3+
import (
4+
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
5+
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
6+
7+
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/info"
8+
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
9+
"github.com/pulumi/pulumi-terraform-bridge/v3/unstable/propertyvalue"
10+
)
11+
12+
type propertyPath resource.PropertyPath
13+
14+
func isForceNew(tfs shim.Schema, ps *SchemaInfo) bool {
15+
return (tfs != nil && tfs.ForceNew()) ||
16+
(ps != nil && ps.ForceNew != nil && *ps.ForceNew)
17+
}
18+
19+
func newPropertyPath(root resource.PropertyKey) propertyPath {
20+
return propertyPath{string(root)}
21+
}
22+
23+
func (k propertyPath) String() string {
24+
return resource.PropertyPath(k).String()
25+
}
26+
27+
func (k propertyPath) Key() detailedDiffKey {
28+
return detailedDiffKey(k.String())
29+
}
30+
31+
func (k propertyPath) append(subkey interface{}) propertyPath {
32+
return append(k, subkey)
33+
}
34+
35+
func (k propertyPath) Subpath(subkey string) propertyPath {
36+
return k.append(subkey)
37+
}
38+
39+
func (k propertyPath) Index(i int) propertyPath {
40+
return k.append(i)
41+
}
42+
43+
func (k propertyPath) IsReservedKey() bool {
44+
leaf := k[len(k)-1]
45+
return leaf == "__meta" || leaf == "__defaults"
46+
}
47+
48+
func lookupSchemas(
49+
path propertyPath, tfs shim.SchemaMap, ps map[string]*info.Schema,
50+
) (shim.Schema, *info.Schema, error) {
51+
schemaPath := PropertyPathToSchemaPath(resource.PropertyPath(path), tfs, ps)
52+
return LookupSchemas(schemaPath, tfs, ps)
53+
}
54+
55+
func propertyPathTriggersReplacement(
56+
path propertyPath, rootTFSchema shim.SchemaMap, rootPulumiSchema map[string]*info.Schema,
57+
) bool {
58+
// A change on a property might trigger a replacement if:
59+
// - The property itself is marked as ForceNew
60+
// - The direct parent property is a collection (list, set, map) and is marked as ForceNew
61+
// See pkg/cross-tests/diff_cross_test.go
62+
// TestAttributeCollectionForceNew, TestBlockCollectionForceNew, TestBlockCollectionElementForceNew
63+
// for a full case study of replacements in TF
64+
tfs, ps, err := lookupSchemas(path, rootTFSchema, rootPulumiSchema)
65+
if err != nil {
66+
return false
67+
}
68+
if isForceNew(tfs, ps) {
69+
return true
70+
}
71+
72+
if len(path) == 1 {
73+
return false
74+
}
75+
76+
parent := path[:len(path)-1]
77+
tfs, ps, err = lookupSchemas(parent, rootTFSchema, rootPulumiSchema)
78+
if err != nil {
79+
return false
80+
}
81+
// Note this is mimicking the TF behaviour, so the effective type is not considered here.
82+
if tfs.Type() != shim.TypeList && tfs.Type() != shim.TypeSet && tfs.Type() != shim.TypeMap {
83+
return false
84+
}
85+
return isForceNew(tfs, ps)
86+
}
87+
88+
func propertyValueTriggersReplacement(
89+
path propertyPath, value resource.PropertyValue, tfs shim.SchemaMap, ps map[string]*info.Schema,
90+
) bool {
91+
replacement := false
92+
visitor := func(subpath resource.PropertyPath, val resource.PropertyValue) (resource.PropertyValue, error) {
93+
if propertyPathTriggersReplacement(propertyPath(subpath), tfs, ps) {
94+
replacement = true
95+
}
96+
return val, nil
97+
}
98+
99+
_, err := propertyvalue.TransformPropertyValue(
100+
resource.PropertyPath(path),
101+
visitor,
102+
value,
103+
)
104+
contract.AssertNoErrorf(err, "TransformPropertyValue should not return an error")
105+
106+
return replacement
107+
}

0 commit comments

Comments
 (0)