github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/configs/synth_body.go (about) 1 package configs 2 3 import ( 4 "fmt" 5 6 "github.com/hashicorp/hcl/v2" 7 "github.com/hashicorp/hcl/v2/hclsyntax" 8 "github.com/zclconf/go-cty/cty" 9 ) 10 11 // SynthBody produces a synthetic hcl.Body that behaves as if it had attributes 12 // corresponding to the elements given in the values map. 13 // 14 // This is useful in situations where, for example, values provided on the 15 // command line can override values given in configuration, using MergeBodies. 16 // 17 // The given filename is used in case any diagnostics are returned. Since 18 // the created body is synthetic, it is likely that this will not be a "real" 19 // filename. For example, if from a command line argument it could be 20 // a representation of that argument's name, such as "-var=...". 21 func SynthBody(filename string, values map[string]cty.Value) hcl.Body { 22 return synthBody{ 23 Filename: filename, 24 Values: values, 25 } 26 } 27 28 type synthBody struct { 29 Filename string 30 Values map[string]cty.Value 31 } 32 33 func (b synthBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) { 34 content, remain, diags := b.PartialContent(schema) 35 remainS := remain.(synthBody) 36 for name := range remainS.Values { 37 diags = append(diags, &hcl.Diagnostic{ 38 Severity: hcl.DiagError, 39 Summary: "Unsupported attribute", 40 Detail: fmt.Sprintf("An attribute named %q is not expected here.", name), 41 Subject: b.synthRange().Ptr(), 42 }) 43 } 44 return content, diags 45 } 46 47 func (b synthBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) { 48 var diags hcl.Diagnostics 49 content := &hcl.BodyContent{ 50 Attributes: make(hcl.Attributes), 51 MissingItemRange: b.synthRange(), 52 } 53 54 remainValues := make(map[string]cty.Value) 55 for attrName, val := range b.Values { 56 remainValues[attrName] = val 57 } 58 59 for _, attrS := range schema.Attributes { 60 delete(remainValues, attrS.Name) 61 val, defined := b.Values[attrS.Name] 62 if !defined { 63 if attrS.Required { 64 diags = append(diags, &hcl.Diagnostic{ 65 Severity: hcl.DiagError, 66 Summary: "Missing required attribute", 67 Detail: fmt.Sprintf("The attribute %q is required, but no definition was found.", attrS.Name), 68 Subject: b.synthRange().Ptr(), 69 }) 70 } 71 continue 72 } 73 content.Attributes[attrS.Name] = b.synthAttribute(attrS.Name, val) 74 } 75 76 // We just ignore blocks altogether, because this body type never has 77 // nested blocks. 78 79 remain := synthBody{ 80 Filename: b.Filename, 81 Values: remainValues, 82 } 83 84 return content, remain, diags 85 } 86 87 func (b synthBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) { 88 ret := make(hcl.Attributes) 89 for name, val := range b.Values { 90 ret[name] = b.synthAttribute(name, val) 91 } 92 return ret, nil 93 } 94 95 func (b synthBody) MissingItemRange() hcl.Range { 96 return b.synthRange() 97 } 98 99 func (b synthBody) synthAttribute(name string, val cty.Value) *hcl.Attribute { 100 rng := b.synthRange() 101 return &hcl.Attribute{ 102 Name: name, 103 Expr: &hclsyntax.LiteralValueExpr{ 104 Val: val, 105 SrcRange: rng, 106 }, 107 NameRange: rng, 108 Range: rng, 109 } 110 } 111 112 func (b synthBody) synthRange() hcl.Range { 113 return hcl.Range{ 114 Filename: b.Filename, 115 Start: hcl.Pos{Line: 1, Column: 1}, 116 End: hcl.Pos{Line: 1, Column: 1}, 117 } 118 }