Skip to content

Commit

Permalink
Merge branch 'main' into dtan4/update-codeowners
Browse files Browse the repository at this point in the history
  • Loading branch information
dtan4 committed Apr 24, 2024
2 parents a24875d + 9104984 commit 5255b99
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 19 deletions.
3 changes: 3 additions & 0 deletions cmd/hcledit/internal/command/fixture/file.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ module "my-module" {
"f",
]

unevaluateable_reference = var.name
unevaluateable_interpolation = "this-${local.reference}"

map_variable = {
bool_variable = true
int_variable = 1
Expand Down
8 changes: 7 additions & 1 deletion cmd/hcledit/internal/command/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

type ReadOptions struct {
OutputFormat string
Fallback bool
}

func NewCmdRead() *cobra.Command {
Expand All @@ -36,6 +37,7 @@ func NewCmdRead() *cobra.Command {
}

cmd.Flags().StringVarP(&opts.OutputFormat, "output-format", "o", "go-template='{{.Value}}'", "format to print the value as")
cmd.Flags().BoolVar(&opts.Fallback, "fallback", false, "falls back to reading the raw value if it cannot be evaluated")

return cmd
}
Expand All @@ -48,7 +50,11 @@ func runRead(opts *ReadOptions, args []string) (string, error) {
return "", fmt.Errorf("failed to read file: %s", err)
}

results, err := editor.Read(query)
readOpts:= []hcledit.Option{}
if opts.Fallback {
readOpts = append(readOpts, hcledit.WithReadFallbackToRawString())
}
results, err := editor.Read(query, readOpts...)
if err != nil {
return "", fmt.Errorf("failed to read file: %s", err)
}
Expand Down
16 changes: 16 additions & 0 deletions cmd/hcledit/internal/command/read_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,22 @@ func TestRunRead(t *testing.T) {
want: "",
opts: defaultOpts,
},
"unevaluateable reference fallback": {
query: "module.my-module.unevaluateable_reference",
want: "var.name",
opts: &ReadOptions{
OutputFormat: "go-template='{{.Value}}'",
Fallback: true,
},
},
"unevaluateable interpolation fallback": {
query: "module.my-module.unevaluateable_interpolation",
want: `"this-${local.reference}"`,
opts: &ReadOptions{
OutputFormat: "go-template='{{.Value}}'",
Fallback: true,
},
},
}

for name, tc := range cases {
Expand Down
2 changes: 1 addition & 1 deletion hcledit.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (h *HCLEditor) Read(queryStr string, opts ...Option) (map[string]interface{
}

results := make(map[string]cty.Value)
hdlr, err := handler.NewReadHandler(results)
hdlr, err := handler.NewReadHandler(results, opt.readFallbackToRawString)
if err != nil {
return nil, err
}
Expand Down
60 changes: 56 additions & 4 deletions hcledit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,21 @@ block "label1" "label2" {
opts: []hcledit.Option{hcledit.WithComment("test comment")},
value: hcledit.BlockVal("label1", "label2"),
want: `
// test comment
block "label1" "label2" {
}
`,
},

"Append block with comment": {
input: `
prev {}`,
query: "block",
opts: []hcledit.Option{hcledit.WithComment("test comment")},
value: hcledit.BlockVal("label1", "label2"),
want: `
prev {}
// test comment
block "label1" "label2" {
}
Expand Down Expand Up @@ -190,15 +205,17 @@ object1 = {

func TestRead(t *testing.T) {
cases := map[string]struct {
input string
query string
want map[string]interface{}
input string
query string
options []hcledit.Option
want map[string]interface{}
}{
"Attribute": {
input: `
attribute = "R"
`,
query: "attribute",
options: make([]hcledit.Option, 0),
want: map[string]interface{}{
"attribute": "R",
},
Expand All @@ -211,6 +228,7 @@ block "label1" "label2" {
attribute = "str"
}
`,
options: make([]hcledit.Option, 0),
query: "block",
want: map[string]interface{}{},
},
Expand All @@ -221,6 +239,7 @@ block "label1" "label2" {
attribute = "R"
}
`,
options: make([]hcledit.Option, 0),
query: "block.label1.label2.attribute",
want: map[string]interface{}{
"block.label1.label2.attribute": "R",
Expand All @@ -235,6 +254,7 @@ block1 "label1" "label2" {
}
}
`,
options: make([]hcledit.Option, 0),
query: "block1.label1.label2.block2.label3.label4.attribute",
want: map[string]interface{}{
"block1.label1.label2.block2.label3.label4.attribute": "R",
Expand All @@ -252,6 +272,7 @@ block "label" "label2" {
}
`,
options: make([]hcledit.Option, 0),
query: "block.label.*.attribute",
want: map[string]interface{}{
"block.label.label1.attribute": "R",
Expand All @@ -265,6 +286,7 @@ object = {
attribute = "R"
}
`,
options: make([]hcledit.Option, 0),
query: "object.attribute",
want: map[string]interface{}{
"object.attribute": "R",
Expand All @@ -278,6 +300,7 @@ object1 = {
}
}
`,
options: make([]hcledit.Option, 0),
query: "object1.object2.attribute",
want: map[string]interface{}{
"object1.object2.attribute": "R",
Expand All @@ -288,6 +311,7 @@ object1 = {
input: `
attribute = 1
`,
options: make([]hcledit.Option, 0),
query: "attribute",
want: map[string]interface{}{
"attribute": 1,
Expand All @@ -298,6 +322,7 @@ attribute = 1
input: `
attribute = "str"
`,
options: make([]hcledit.Option, 0),
query: "attribute",
want: map[string]interface{}{
"attribute": "str",
Expand All @@ -308,6 +333,7 @@ attribute = "str"
input: `
attribute = true
`,
options: make([]hcledit.Option, 0),
query: "attribute",
want: map[string]interface{}{
"attribute": true,
Expand All @@ -318,6 +344,7 @@ attribute = true
input: `
attribute = false
`,
options: make([]hcledit.Option, 0),
query: "attribute",
want: map[string]interface{}{
"attribute": false,
Expand All @@ -328,6 +355,7 @@ attribute = false
input: `
attribute = ["str1", "str2", "str3"]
`,
options: make([]hcledit.Option, 0),
query: "attribute",
want: map[string]interface{}{
"attribute": []string{"str1", "str2", "str3"},
Expand All @@ -338,6 +366,7 @@ attribute = ["str1", "str2", "str3"]
input: `
attribute = [1, 2, 3]
`,
options: make([]hcledit.Option, 0),
query: "attribute",
want: map[string]interface{}{
"attribute": []int{1, 2, 3},
Expand All @@ -348,11 +377,34 @@ attribute = [1, 2, 3]
input: `
attribute = [true, false, true]
`,
options: make([]hcledit.Option, 0),
query: "attribute",
want: map[string]interface{}{
"attribute": []bool{true, false, true},
},
},

"fallback to absolute variable name": {
input: `
attribute = local.var
`,
options: []hcledit.Option{hcledit.WithReadFallbackToRawString()},
query: "attribute",
want: map[string]interface{}{
"attribute": "local.var",
},
},

"fallback to uninterpolated string": {
input: `
attribute = "some-${local.var}"
`,
options: []hcledit.Option{hcledit.WithReadFallbackToRawString()},
query: "attribute",
want: map[string]interface{}{
"attribute": `"some-${local.var}"`,
},
},
}

for name, tc := range cases {
Expand All @@ -363,7 +415,7 @@ attribute = [true, false, true]
t.Fatal(err)
}

got, err := editor.Read(tc.query)
got, err := editor.Read(tc.query, tc.options...)
if err != nil {
t.Fatal(err)
}
Expand Down
11 changes: 9 additions & 2 deletions internal/handler/block.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package handler

import (
"strings"
"fmt"
"strings"

"github.com/hashicorp/hcl/v2/hclwrite"

Expand All @@ -26,7 +26,14 @@ func newBlockHandler(labels []string, comment string) (Handler, error) {
}

func (h *blockHandler) HandleBody(body *hclwrite.Body, name string, _ []string) error {
body.AppendUnstructuredTokens(beforeTokens(fmt.Sprintf("// %s", strings.TrimSpace(strings.TrimPrefix(h.comment, "//"))), false))
if h.comment != "" {
body.AppendUnstructuredTokens(
beforeTokens(
fmt.Sprintf("// %s", strings.TrimSpace(strings.TrimPrefix(h.comment, "//"))),
true,
),
)
}

body.AppendNewBlock(name, h.labels)
return nil
Expand Down
25 changes: 17 additions & 8 deletions internal/handler/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@ import (
)

type readHandler struct {
results map[string]cty.Value
results map[string]cty.Value
fallbackToRawString bool
}

func NewReadHandler(results map[string]cty.Value) (Handler, error) {
func NewReadHandler(results map[string]cty.Value, fallbackToRawString bool) (Handler, error) {
return &readHandler{
results: results,
results: results,
fallbackToRawString: fallbackToRawString,
}, nil
}

func (h *readHandler) HandleBody(body *hclwrite.Body, name string, keyTrail []string) error {
buf := body.GetAttribute(name).BuildTokens(nil).Bytes()
value, err := parse(buf, name)
value, err := parse(buf, name, h.fallbackToRawString)
if err != nil {
return err
}
Expand All @@ -33,24 +35,31 @@ func (h *readHandler) HandleBody(body *hclwrite.Body, name string, keyTrail []st

func (h *readHandler) HandleObject(object *ast.Object, name string, keyTrail []string) error {
buf := object.GetObjectAttribute(name).BuildTokens().Bytes()
value, err := parse(buf, name)
value, err := parse(buf, name, h.fallbackToRawString)
if err != nil {
return err
}
h.results[strings.Join(keyTrail, ".")] = value
return nil
}

func parse(buf []byte, name string) (cty.Value, error) {
func parse(buf []byte, name string, fallback bool) (cty.Value, error) {
file, diags := hclsyntax.ParseConfig(buf, "", hcl.Pos{Line: 1, Column: 1})
if diags.HasErrors() {
return cty.Value{}, diags
}

body := file.Body.(*hclsyntax.Body)
v, diags := body.Attributes[name].Expr.Value(nil)
expr := body.Attributes[name].Expr
v, diags := expr.Value(nil)
if diags.HasErrors() {
return cty.Value{}, diags
if !fallback {
return cty.Value{}, diags
}

// Could not parse the value with a nil EvalContext, so this is likely an
// interpolated string. Instead, attempt to parse the raw string value.
return cty.StringVal(string(expr.Range().SliceBytes(buf))), nil
}
return v, nil
}
13 changes: 10 additions & 3 deletions option.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package hcledit

type option struct {
comment string
afterKey string
beforeNewline bool
comment string
afterKey string
beforeNewline bool
readFallbackToRawString bool
}

// Option configures specific behavior for specific HCLEditor operations.
Expand All @@ -30,3 +31,9 @@ func WithNewLine() Option {
opt.beforeNewline = true
}
}

func WithReadFallbackToRawString() Option {
return func(opt *option) {
opt.readFallbackToRawString = true
}
}

0 comments on commit 5255b99

Please sign in to comment.