github.com/beauknowssoftware/makehcl@v0.0.0-20200322000747-1b9bb1e1c008/internal/parse/getGlobals.go (about) 1 package parse 2 3 import ( 4 "fmt" 5 6 "github.com/hashicorp/hcl/v2" 7 "github.com/pkg/errors" 8 "github.com/zclconf/go-cty/cty" 9 ) 10 11 type global struct { 12 globalType string 13 attr *hcl.Attribute 14 } 15 16 func (g global) name() globalName { 17 return globalName{ 18 globalType: g.globalType, 19 name: g.attr.Name, 20 } 21 } 22 23 type globalName struct { 24 globalType string 25 name string 26 } 27 28 type globalSorter struct { 29 globals map[globalName]global 30 sorted []global 31 visited map[globalName]bool 32 visiting map[globalName]bool 33 } 34 35 func (s *globalSorter) visit(g global) { 36 if s.visited[g.name()] { 37 return 38 } 39 40 if s.visiting[g.name()] { 41 panic(fmt.Sprintf("env loopback on %v", g.name())) 42 } 43 44 s.visiting[g.name()] = true 45 46 for _, v := range g.attr.Expr.Variables() { 47 globalType := v.RootName() 48 spl := v.SimpleSplit() 49 50 if spl.Rel == nil || len(spl.Rel) == 0 { 51 continue 52 } 53 54 name := spl.Rel[0].(hcl.TraverseAttr).Name 55 gName := globalName{globalType, name} 56 57 if g.name() == gName && globalType == "env" { 58 continue 59 } 60 61 if gl, hasGlobal := s.globals[gName]; hasGlobal { 62 s.visit(gl) 63 } 64 } 65 66 s.visiting[g.name()] = false 67 s.visited[g.name()] = true 68 s.sorted = append(s.sorted, g) 69 } 70 71 func (s *globalSorter) sort() { 72 s.visited = make(map[globalName]bool) 73 s.visiting = make(map[globalName]bool) 74 75 for _, a := range s.globals { 76 s.visit(a) 77 } 78 } 79 80 func getGlobals(attrSets map[string]map[string]*hcl.Attribute, ctx *hcl.EvalContext) (map[string]string, error) { 81 s := globalSorter{ 82 globals: make(map[globalName]global), 83 } 84 85 for globalType, attr := range attrSets { 86 for _, a := range attr { 87 g := global{ 88 globalType: globalType, 89 attr: a, 90 } 91 s.globals[g.name()] = g 92 } 93 } 94 95 s.sort() 96 97 vars := make(map[string]cty.Value) 98 envResult := make(map[string]string) 99 envs := ctx.Variables["env"].AsValueMap() 100 101 for _, a := range s.sorted { 102 if a.globalType == "var" { 103 val, diag := a.attr.Expr.Value(ctx) 104 vars[a.attr.Name] = val 105 106 if diag.HasErrors() { 107 return nil, errors.Wrap(diag, "failed to get var attributes") 108 } 109 110 ctx.Variables["var"] = cty.ObjectVal(vars) 111 } else if a.globalType == "env" { 112 val, diag := a.attr.Expr.Value(ctx) 113 envs[a.attr.Name] = val 114 envResult[a.attr.Name] = val.AsString() 115 if diag.HasErrors() { 116 return nil, errors.Wrap(diag, "failed to get env attributes") 117 } 118 ctx.Variables["env"] = cty.ObjectVal(envs) 119 } 120 } 121 122 return envResult, nil 123 }