Skip to content

Commit 1bdacc5

Browse files
committed
reduce duplication
1 parent 12b8e05 commit 1bdacc5

File tree

3 files changed

+100
-108
lines changed

3 files changed

+100
-108
lines changed

internal/convert/adv2v2.go

Lines changed: 30 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,9 @@ func convertDynamicRepSpecs(resourceb *hclwrite.Body, dSpec dynamicBlock, diskSi
171171
}
172172

173173
// Create the for expression for the flattened replication_specs
174-
forExpr := fmt.Sprintf("for %s in %s : [\n for i in range(%s) : ",
175-
nSpec, hcl.GetAttrExpr(dSpec.forEach), numShardsExpr)
174+
outerFor := buildForExpression(nSpec, hcl.GetAttrExpr(dSpec.forEach))
175+
innerFor := buildForExpressionWithIndex("i", fmt.Sprintf("range(%s)", numShardsExpr))
176+
forExpr := fmt.Sprintf("%s [\n %s", outerFor, innerFor)
176177
tokens := hcl.TokensFromExpr(forExpr)
177178
tokens = append(tokens, hcl.TokensObject(dSpec.content.Body())...)
178179
tokens = append(tokens, hcl.TokensFromExpr("\n ]\n]")...)
@@ -190,7 +191,7 @@ func convertDynamicRepSpecs(resourceb *hclwrite.Body, dSpec dynamicBlock, diskSi
190191
}
191192

192193
// Create the for expression without num_shards
193-
forExpr := fmt.Sprintf("for %s in %s :", nSpec, hcl.GetAttrExpr(dSpec.forEach))
194+
forExpr := buildForExpression(nSpec, hcl.GetAttrExpr(dSpec.forEach))
194195
tokens := hcl.TokensFromExpr(forExpr)
195196
tokens = append(tokens, hcl.TokensObject(dSpec.content.Body())...)
196197
tokens = hcl.EncloseBracketsNewLines(tokens)
@@ -208,16 +209,7 @@ func processRegionConfigBlocks(targetBody *hclwrite.Body, blocks []*hclwrite.Blo
208209
blockBody := blockFile.Body()
209210

210211
// Copy all attributes in deterministic order
211-
attrs := block.Body().Attributes()
212-
var names []string
213-
for name := range attrs {
214-
names = append(names, name)
215-
}
216-
slices.Sort(names)
217-
for _, name := range names {
218-
attr := attrs[name]
219-
blockBody.SetAttributeRaw(name, hcl.TokensFromExpr(hcl.GetAttrExpr(attr)))
220-
}
212+
copyAttributesSorted(blockBody, block.Body().Attributes())
221213

222214
// Add disk_size_gb to specs blocks if needed
223215
if diskSizeGB != nil && (blockType == nElectableSpecs ||
@@ -242,31 +234,12 @@ func convertDynamicRepSpecsWithDynamicConfig(resourceb *hclwrite.Body, dSpec, dC
242234
// Transform references in place for the dynamic config content
243235
transformDynamicBlockReferencesRecursive(dConfig.content.Body(), configBlockName, nRegion)
244236
// Also transform outer references (with deterministic ordering)
245-
attrs := dConfig.content.Body().Attributes()
246-
var attrNames []string
247-
for name := range attrs {
248-
attrNames = append(attrNames, name)
249-
}
250-
slices.Sort(attrNames)
251-
for _, name := range attrNames {
252-
attr := attrs[name]
253-
expr := hcl.GetAttrExpr(attr)
254-
expr = replaceDynamicBlockReferences(expr, nRepSpecs, nSpec)
255-
dConfig.content.Body().SetAttributeRaw(name, hcl.TokensFromExpr(expr))
237+
transform := func(expr string) string {
238+
return replaceDynamicBlockReferences(expr, nRepSpecs, nSpec)
256239
}
240+
transformAttributesSorted(dConfig.content.Body(), dConfig.content.Body().Attributes(), transform)
257241
for _, block := range dConfig.content.Body().Blocks() {
258-
blockAttrs := block.Body().Attributes()
259-
var blockAttrNames []string
260-
for name := range blockAttrs {
261-
blockAttrNames = append(blockAttrNames, name)
262-
}
263-
slices.Sort(blockAttrNames)
264-
for _, name := range blockAttrNames {
265-
attr := blockAttrs[name]
266-
expr := hcl.GetAttrExpr(attr)
267-
expr = replaceDynamicBlockReferences(expr, nRepSpecs, nSpec)
268-
block.Body().SetAttributeRaw(name, hcl.TokensFromExpr(expr))
269-
}
242+
transformAttributesSorted(block.Body(), block.Body().Attributes(), transform)
270243
}
271244

272245
// Build the expression using HCL functions
@@ -278,22 +251,13 @@ func convertDynamicRepSpecsWithDynamicConfig(resourceb *hclwrite.Body, dSpec, dC
278251
regionConfigBody := regionConfigFile.Body()
279252

280253
// Copy all attributes in deterministic order
281-
configAttrs := dConfig.content.Body().Attributes()
282-
var configAttrNames []string
283-
for name := range configAttrs {
284-
configAttrNames = append(configAttrNames, name)
285-
}
286-
slices.Sort(configAttrNames)
287-
for _, name := range configAttrNames {
288-
attr := configAttrs[name]
289-
regionConfigBody.SetAttributeRaw(name, hcl.TokensFromExpr(hcl.GetAttrExpr(attr)))
290-
}
254+
copyAttributesSorted(regionConfigBody, dConfig.content.Body().Attributes())
291255

292256
// Add all blocks generically as objects
293257
processRegionConfigBlocks(regionConfigBody, dConfig.content.Body().Blocks(), diskSizeGB)
294258

295259
// Build the region_configs for expression
296-
regionForExpr := fmt.Sprintf("for %s in %s :", nRegion, configForEach)
260+
regionForExpr := buildForExpression(nRegion, configForEach)
297261
regionTokens := hcl.TokensFromExpr(regionForExpr)
298262
regionTokens = append(regionTokens, hcl.TokensObject(regionConfigBody)...)
299263

@@ -309,12 +273,12 @@ func convertDynamicRepSpecsWithDynamicConfig(resourceb *hclwrite.Body, dSpec, dC
309273
repSpecBody.SetAttributeRaw(nConfig, hcl.EncloseBracketsNewLines(regionTokens))
310274

311275
// Build the inner for expression with range
312-
innerForExpr := fmt.Sprintf("for i in range(%s) :", numShardsExpr)
276+
innerForExpr := buildForExpressionWithIndex("i", fmt.Sprintf("range(%s)", numShardsExpr))
313277
innerTokens := hcl.TokensFromExpr(innerForExpr)
314278
innerTokens = append(innerTokens, hcl.TokensObject(repSpecBody)...)
315279

316280
// Build the outer for expression
317-
outerForExpr := fmt.Sprintf("for %s in %s : ", nSpec, hcl.GetAttrExpr(dSpec.forEach))
281+
outerForExpr := buildForExpression(nSpec, hcl.GetAttrExpr(dSpec.forEach))
318282
outerTokens := hcl.TokensFromExpr(outerForExpr)
319283
outerTokens = append(outerTokens, hcl.EncloseBracketsNewLines(innerTokens)...)
320284

@@ -332,21 +296,14 @@ func convertDynamicRepSpecsWithDynamicConfig(resourceb *hclwrite.Body, dSpec, dC
332296
// Helper function to add attributes with transformation
333297
func addAttributesWithTransform(targetBody *hclwrite.Body, sourceAttrs map[string]*hclwrite.Attribute,
334298
configBlockName string) {
335-
// Sort attribute names for deterministic output
336-
var names []string
337-
for name := range sourceAttrs {
338-
names = append(names, name)
339-
}
340-
slices.Sort(names)
341-
for _, name := range names {
342-
attr := sourceAttrs[name]
343-
expr := hcl.GetAttrExpr(attr)
344-
// First replace nested dynamic block references
345-
expr = replaceDynamicBlockReferences(expr, configBlockName, nRegion)
346-
// Then replace outer dynamic block references
347-
expr = replaceDynamicBlockReferences(expr, nRepSpecs, nSpec)
348-
targetBody.SetAttributeRaw(name, hcl.TokensFromExpr(expr))
299+
// Apply transformations in order
300+
transform1 := func(expr string) string {
301+
return replaceDynamicBlockReferences(expr, configBlockName, nRegion)
302+
}
303+
transform2 := func(expr string) string {
304+
return replaceDynamicBlockReferences(expr, nRepSpecs, nSpec)
349305
}
306+
transformAttributesSorted(targetBody, sourceAttrs, transform1, transform2)
350307
}
351308

352309
func convertDynamicRepSpecsWithoutNumShards(resourceb *hclwrite.Body, dSpec, dConfig dynamicBlock,
@@ -375,26 +332,22 @@ func convertDynamicRepSpecsWithoutNumShards(resourceb *hclwrite.Body, dSpec, dCo
375332
}
376333

377334
// Process specs
378-
fillSpecOpt(configb, nElectableSpecs, diskSizeGB)
379-
fillSpecOpt(configb, nReadOnlySpecs, diskSizeGB)
380-
fillSpecOpt(configb, nAnalyticsSpecs, diskSizeGB)
381-
fillSpecOpt(configb, nAutoScaling, nil)
382-
fillSpecOpt(configb, nAnalyticsAutoScaling, nil)
335+
processAllSpecs(configb, diskSizeGB)
383336

384337
// Build the nested for expression for region_configs
385338
// Use standardized property name (region_configs) instead of the actual for_each collection
386339
configForEach := fmt.Sprintf("%s.%s", nSpec, nConfig)
387340

388341
// Build the region_configs for expression
389-
regionForExpr := fmt.Sprintf("for %s in %s :", nRegion, configForEach)
342+
regionForExpr := buildForExpression(nRegion, configForEach)
390343
regionTokens := hcl.TokensFromExpr(regionForExpr)
391344
regionTokens = append(regionTokens, hcl.TokensObject(configb)...)
392345

393346
repSpecb.SetAttributeRaw(nConfig, hcl.EncloseBracketsNewLines(regionTokens))
394347

395348
// Build the for expression as an array wrapped in flatten
396349
// Format: flatten([for spec in ... : [ { ... } ] ])
397-
forExpr := fmt.Sprintf("for %s in %s : ", nSpec, hcl.GetAttrExpr(dSpec.forEach))
350+
forExpr := buildForExpression(nSpec, hcl.GetAttrExpr(dSpec.forEach))
398351
innerTokens := hcl.TokensFromExpr(forExpr)
399352
innerTokens = append(innerTokens, hcl.TokensArraySingle(repSpecb)...)
400353

@@ -432,11 +385,7 @@ func convertConfig(repSpecs *hclwrite.Body, diskSizeGB hclwrite.Tokens) error {
432385
}
433386
repSpecs.RemoveBlock(block)
434387
blockb := block.Body()
435-
fillSpecOpt(blockb, nElectableSpecs, diskSizeGB)
436-
fillSpecOpt(blockb, nReadOnlySpecs, diskSizeGB)
437-
fillSpecOpt(blockb, nAnalyticsSpecs, diskSizeGB)
438-
fillSpecOpt(blockb, nAutoScaling, nil) // auto_scaling doesn't need disk_size_gb
439-
fillSpecOpt(blockb, nAnalyticsAutoScaling, nil) // analytics_auto_scaling doesn't need disk_size_gb
388+
processAllSpecs(blockb, diskSizeGB)
440389
configs = append(configs, blockb)
441390
}
442391
if len(configs) == 0 {
@@ -454,14 +403,10 @@ func convertDynamicConfig(repSpecs *hclwrite.Body, dConfig dynamicBlock, diskSiz
454403
transformDynamicBlockReferencesRecursive(dConfig.content.Body(), blockName, nRegion)
455404

456405
// Process specs
457-
fillSpecOpt(dConfig.content.Body(), nElectableSpecs, diskSizeGB)
458-
fillSpecOpt(dConfig.content.Body(), nReadOnlySpecs, diskSizeGB)
459-
fillSpecOpt(dConfig.content.Body(), nAnalyticsSpecs, diskSizeGB)
460-
fillSpecOpt(dConfig.content.Body(), nAutoScaling, nil)
461-
fillSpecOpt(dConfig.content.Body(), nAnalyticsAutoScaling, nil)
406+
processAllSpecs(dConfig.content.Body(), diskSizeGB)
462407

463408
// Build the for expression
464-
forExpr := fmt.Sprintf("for %s in %s :", nRegion, hcl.GetAttrExpr(dConfig.forEach))
409+
forExpr := buildForExpression(nRegion, hcl.GetAttrExpr(dConfig.forEach))
465410
tokens := hcl.TokensFromExpr(forExpr)
466411
tokens = append(tokens, hcl.TokensObject(dConfig.content.Body())...)
467412
tokens = hcl.EncloseBracketsNewLines(tokens)
@@ -473,36 +418,17 @@ func convertDynamicConfig(repSpecs *hclwrite.Body, dConfig dynamicBlock, diskSiz
473418

474419
func transformDynamicBlockReferencesRecursive(body *hclwrite.Body, blockName, varName string) {
475420
// Transform attributes in deterministic order
476-
attrs := body.Attributes()
477-
var names []string
478-
for name := range attrs {
479-
names = append(names, name)
480-
}
481-
slices.Sort(names)
482-
for _, name := range names {
483-
attr := attrs[name]
484-
expr := replaceDynamicBlockReferences(hcl.GetAttrExpr(attr), blockName, varName)
485-
body.SetAttributeRaw(name, hcl.TokensFromExpr(expr))
421+
transform := func(expr string) string {
422+
return replaceDynamicBlockReferences(expr, blockName, varName)
486423
}
424+
transformAttributesSorted(body, body.Attributes(), transform)
425+
487426
// Transform nested blocks
488427
for _, block := range body.Blocks() {
489428
transformDynamicBlockReferencesRecursive(block.Body(), blockName, varName)
490429
}
491430
}
492431

493-
func fillSpecOpt(resourceb *hclwrite.Body, name string, diskSizeGBTokens hclwrite.Tokens) {
494-
block := resourceb.FirstMatchingBlock(name, nil)
495-
if block == nil {
496-
return
497-
}
498-
if diskSizeGBTokens != nil {
499-
blockb := block.Body()
500-
blockb.RemoveAttribute(nDiskSizeGB)
501-
blockb.SetAttributeRaw(nDiskSizeGB, diskSizeGBTokens)
502-
}
503-
fillBlockOpt(resourceb, name)
504-
}
505-
506432
// hasExpectedBlocksAsAttributes checks if any of the expected block names
507433
// exist as attributes in the resource body. In that case conversion is not done
508434
// as advanced cluster is not in a valid SDKv2 configuration.

internal/convert/clu2adv.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ func fillReplicationSpecsWithDynamicBlock(resourceb *hclwrite.Body, root attrVal
371371
if err != nil {
372372
return dynamicBlock{}, err
373373
}
374-
forSpec := hcl.TokensFromExpr(fmt.Sprintf("for %s in %s : ", nSpec, hcl.GetAttrExpr(dSpec.forEach)))
374+
forSpec := hcl.TokensFromExpr(buildForExpression(nSpec, hcl.GetAttrExpr(dSpec.forEach)))
375375
forSpec = append(forSpec, dConfig.tokens...)
376376
tokens := hcl.TokensFuncFlatten(forSpec)
377377
dSpec.tokens = tokens
@@ -397,7 +397,7 @@ func fillWithDynamicRegionConfigs(specbSrc *hclwrite.Body, root attrVals, change
397397
if err != nil {
398398
return dynamicBlock{}, err
399399
}
400-
priorityForStr := fmt.Sprintf("for %s in range(%d, %d, -1) : ", nPriority, valMaxPriority, valMinPriority)
400+
priorityForStr := buildForExpression(nPriority, fmt.Sprintf("range(%d, %d, -1)", valMaxPriority, valMinPriority))
401401
priorityFor := hcl.TokensComment(commentPriorityFor)
402402
priorityFor = append(priorityFor, hcl.TokensFromExpr(priorityForStr)...)
403403
priorityFor = append(priorityFor, regionFor...)
@@ -407,7 +407,7 @@ func fillWithDynamicRegionConfigs(specbSrc *hclwrite.Body, root attrVals, change
407407
if shards == nil {
408408
return dynamicBlock{}, fmt.Errorf("%s: %s not found", errRepSpecs, nNumShards)
409409
}
410-
tokens := hcl.TokensFromExpr(fmt.Sprintf("for i in range(%s) :", hcl.GetAttrExpr(shards)))
410+
tokens := hcl.TokensFromExpr(buildForExpressionWithIndex("i", fmt.Sprintf("range(%s)", hcl.GetAttrExpr(shards))))
411411
tokens = append(tokens, hcl.EncloseBraces(repSpec.BuildTokens(nil), true)...)
412412
d.tokens = hcl.EncloseBracketsNewLines(tokens)
413413
return d, nil
@@ -563,7 +563,7 @@ func getDynamicBlockRegionArray(forEach string, configSrc *hclwrite.Block, root
563563
if err != nil {
564564
return nil, err
565565
}
566-
tokens := hcl.TokensFromExpr(fmt.Sprintf("for %s in %s :", nRegion, forEach))
566+
tokens := hcl.TokensFromExpr(buildForExpression(nRegion, forEach))
567567
tokens = append(tokens, hcl.EncloseBraces(region.BuildTokens(nil), true)...)
568568
tokens = append(tokens, hcl.TokensFromExpr(fmt.Sprintf("if %s == %s", nPriority, priorityStr))...)
569569
return hcl.EncloseBracketsNewLines(tokens), nil

internal/convert/shared.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package convert
22

33
import (
44
"fmt"
5+
"slices"
56
"strings"
67

78
"github.com/hashicorp/hcl/v2/hclwrite"
@@ -129,3 +130,68 @@ func fillAdvConfigOpt(resourceb *hclwrite.Body) {
129130

130131
fillBlockOpt(resourceb, nAdvConfig)
131132
}
133+
134+
// copyAttributesSorted copies attributes from source to target in sorted order for deterministic output
135+
func copyAttributesSorted(targetBody *hclwrite.Body, sourceAttrs map[string]*hclwrite.Attribute) {
136+
var names []string
137+
for name := range sourceAttrs {
138+
names = append(names, name)
139+
}
140+
slices.Sort(names)
141+
for _, name := range names {
142+
attr := sourceAttrs[name]
143+
targetBody.SetAttributeRaw(name, hcl.TokensFromExpr(hcl.GetAttrExpr(attr)))
144+
}
145+
}
146+
147+
// transformAttributesSorted transforms and copies attributes in sorted order
148+
func transformAttributesSorted(targetBody *hclwrite.Body, sourceAttrs map[string]*hclwrite.Attribute,
149+
transforms ...func(string) string) {
150+
var names []string
151+
for name := range sourceAttrs {
152+
names = append(names, name)
153+
}
154+
slices.Sort(names)
155+
for _, name := range names {
156+
attr := sourceAttrs[name]
157+
expr := hcl.GetAttrExpr(attr)
158+
// Apply all transformations
159+
for _, transform := range transforms {
160+
expr = transform(expr)
161+
}
162+
targetBody.SetAttributeRaw(name, hcl.TokensFromExpr(expr))
163+
}
164+
}
165+
166+
// processAllSpecs processes all spec blocks (electable, read_only, analytics) and auto_scaling blocks
167+
func processAllSpecs(body *hclwrite.Body, diskSizeGB hclwrite.Tokens) {
168+
fillSpecOpt(body, nElectableSpecs, diskSizeGB)
169+
fillSpecOpt(body, nReadOnlySpecs, diskSizeGB)
170+
fillSpecOpt(body, nAnalyticsSpecs, diskSizeGB)
171+
fillSpecOpt(body, nAutoScaling, nil)
172+
fillSpecOpt(body, nAnalyticsAutoScaling, nil)
173+
}
174+
175+
// fillSpecOpt converts a spec block to an attribute with object value and optionally adds disk_size_gb
176+
func fillSpecOpt(resourceb *hclwrite.Body, name string, diskSizeGBTokens hclwrite.Tokens) {
177+
block := resourceb.FirstMatchingBlock(name, nil)
178+
if block == nil {
179+
return
180+
}
181+
if diskSizeGBTokens != nil {
182+
blockb := block.Body()
183+
blockb.RemoveAttribute(nDiskSizeGB)
184+
blockb.SetAttributeRaw(nDiskSizeGB, diskSizeGBTokens)
185+
}
186+
fillBlockOpt(resourceb, name)
187+
}
188+
189+
// buildForExpression builds a for expression with the given variable and collection
190+
func buildForExpression(varName, collection string) string {
191+
return fmt.Sprintf("for %s in %s : ", varName, collection)
192+
}
193+
194+
// buildForExpressionWithIndex builds a for expression with an index variable
195+
func buildForExpressionWithIndex(indexVar, collection string) string {
196+
return fmt.Sprintf("for %s in %s : ", indexVar, collection)
197+
}

0 commit comments

Comments
 (0)