|
1 | 1 | package cli
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "encoding/json" |
| 5 | + "fmt" |
4 | 6 | "os"
|
5 | 7 | "path/filepath"
|
| 8 | + "sort" |
6 | 9 | "strings"
|
7 | 10 |
|
8 | 11 | "golang.org/x/xerrors"
|
9 | 12 | "gopkg.in/yaml.v3"
|
10 | 13 |
|
| 14 | + "github.com/hashicorp/hcl/v2/hclparse" |
| 15 | + "github.com/zclconf/go-cty/cty" |
| 16 | + |
11 | 17 | "github.com/coder/coder/v2/codersdk"
|
12 | 18 | )
|
13 | 19 |
|
@@ -94,12 +100,77 @@ func parseVariableValuesFromVarsFiles(varsFiles []string) ([]codersdk.VariableVa
|
94 | 100 | return parsed, nil
|
95 | 101 | }
|
96 | 102 |
|
97 |
| -func parseVariableValuesFromHCL(hcl []byte) ([]codersdk.VariableValue, error) { |
98 |
| - panic("not implemented yet") |
| 103 | +func parseVariableValuesFromHCL(content []byte) ([]codersdk.VariableValue, error) { |
| 104 | + parser := hclparse.NewParser() |
| 105 | + hclFile, diags := parser.ParseHCL(content, "file.hcl") |
| 106 | + if diags.HasErrors() { |
| 107 | + return nil, diags |
| 108 | + } |
| 109 | + |
| 110 | + attrs, diags := hclFile.Body.JustAttributes() |
| 111 | + if diags.HasErrors() { |
| 112 | + return nil, diags |
| 113 | + } |
| 114 | + |
| 115 | + var stringData map[string]string |
| 116 | + for _, attribute := range attrs { |
| 117 | + ctyValue, diags := attribute.Expr.Value(nil) |
| 118 | + if diags.HasErrors() { |
| 119 | + return nil, diags |
| 120 | + } |
| 121 | + |
| 122 | + ctyType := ctyValue.Type() |
| 123 | + if ctyType.Equals(cty.String) { |
| 124 | + stringData[attribute.Name] = ctyValue.AsString() |
| 125 | + } else if ctyType.Equals(cty.Number) { |
| 126 | + stringData[attribute.Name] = ctyValue.AsBigFloat().String() |
| 127 | + } else if ctyType.IsListType() { |
| 128 | + stringData[attribute.Name] = "TODO list(string)" |
| 129 | + } |
| 130 | + } |
| 131 | + |
| 132 | + return convertMapIntoVariableValues(stringData), nil |
| 133 | +} |
| 134 | + |
| 135 | +// parseVariableValuesFromJSON converts the .tfvars.json content into template variables. |
| 136 | +// The function visits only root-level properties as template variables do not support nested |
| 137 | +// structures. |
| 138 | +func parseVariableValuesFromJSON(content []byte) ([]codersdk.VariableValue, error) { |
| 139 | + var data map[string]interface{} |
| 140 | + err := json.Unmarshal(content, &data) |
| 141 | + if err != nil { |
| 142 | + return nil, err |
| 143 | + } |
| 144 | + |
| 145 | + stringData := make(map[string]string) |
| 146 | + for key, value := range data { |
| 147 | + switch value.(type) { |
| 148 | + case string, int, bool: |
| 149 | + stringData[key] = fmt.Sprintf("%v", value) |
| 150 | + default: |
| 151 | + m, err := json.Marshal(value) |
| 152 | + if err != nil { |
| 153 | + return nil, err |
| 154 | + } |
| 155 | + stringData[key] = string(m) |
| 156 | + } |
| 157 | + } |
| 158 | + |
| 159 | + return convertMapIntoVariableValues(stringData), nil |
99 | 160 | }
|
100 | 161 |
|
101 |
| -func parseVariableValuesFromJSON(json []byte) ([]codersdk.VariableValue, error) { |
102 |
| - panic("not implemented yet") |
| 162 | +func convertMapIntoVariableValues(m map[string]string) []codersdk.VariableValue { |
| 163 | + var parsed []codersdk.VariableValue |
| 164 | + for key, value := range m { |
| 165 | + parsed = append(parsed, codersdk.VariableValue{ |
| 166 | + Name: key, |
| 167 | + Value: value, |
| 168 | + }) |
| 169 | + } |
| 170 | + sort.Slice(parsed, func(i, j int) bool { |
| 171 | + return parsed[i].Name < parsed[j].Name |
| 172 | + }) |
| 173 | + return parsed |
103 | 174 | }
|
104 | 175 |
|
105 | 176 | func parseVariableValuesFromFile(variablesFile string) ([]codersdk.VariableValue, error) {
|
|
0 commit comments