github.com/Yunsang-Jeong/terraforge@v0.0.0-20231003081416-fe4fad2c57e3/internal/configs/config.go (about) 1 package configs 2 3 import ( 4 "errors" 5 "fmt" 6 "path/filepath" 7 8 "github.com/hashicorp/hcl/v2" 9 "github.com/hashicorp/hcl/v2/hclsyntax" 10 "github.com/hashicorp/hcl/v2/hclwrite" 11 "github.com/spf13/afero" 12 "github.com/zclconf/go-cty/cty" 13 ) 14 15 type Config struct { 16 Metafile *Metafile 17 Generates map[string][]*Generate 18 Ctx *hcl.EvalContext 19 } 20 21 func (c *Config) GenerateTFConfig(workingDir string, fs afero.Afero) error { 22 for label0, generates := range c.Generates { 23 file := hclwrite.NewEmptyFile() 24 body := file.Body() 25 26 for index, generate := range generates { 27 if !generate.When { 28 continue 29 } 30 31 ctx := c.Ctx.NewChild() 32 ctx.Variables = map[string]cty.Value{} 33 34 if generate.ForEach != nil { 35 for key, value := range generate.ForEach { 36 ctx.Variables = map[string]cty.Value{ 37 "each": cty.ObjectVal(map[string]cty.Value{ 38 "key": cty.StringVal(key), 39 "value": value, 40 }), 41 } 42 43 newBlock := body.AppendNewBlock(label0, generate.Labels[1:]) 44 newBlockBody := newBlock.Body() 45 46 if err := appendBlockContent(newBlockBody, generate.Config, ctx); err != nil { 47 return err 48 } 49 50 if index < len(generate.Config.Blocks)-1 { 51 body.AppendNewline() 52 } 53 } 54 } else { 55 newBlock := body.AppendNewBlock(label0, generate.Labels[1:]) 56 newBlockBody := newBlock.Body() 57 58 if err := appendBlockContent(newBlockBody, generate.Config, ctx); err != nil { 59 return err 60 } 61 62 if index < len(generate.Config.Blocks)-1 { 63 body.AppendNewline() 64 } 65 } 66 } 67 68 filename := filepath.Join(workingDir, fmt.Sprintf("%s.tf", label0)) 69 if err := fs.WriteFile(filename, file.Bytes(), 0644); err != nil { 70 return err 71 } 72 } 73 74 return nil 75 } 76 77 func appendBlockContent(file *hclwrite.Body, config *hclsyntax.Body, ctx *hcl.EvalContext) error { 78 attributes := map[string]cty.Value{} 79 for name, attribute := range config.Attributes { 80 value, diags := attribute.Expr.Value(ctx) 81 if diags.HasErrors() { 82 return errors.Join(diags.Errs()...) 83 } 84 85 attributes[name] = value 86 } 87 88 for name, attribute := range attributes { 89 file.SetAttributeValue(name, attribute) 90 } 91 92 for _, block := range config.Blocks { 93 blockInBlock := file.AppendNewBlock(block.Type, []string{}) 94 blockInBlockBody := blockInBlock.Body() 95 96 if err := appendBlockContent(blockInBlockBody, block.Body, ctx); err != nil { 97 return err 98 } 99 } 100 101 return nil 102 }