-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #22 from jrhouston/remove-tf-dep
Remove dependency on terraform project
- Loading branch information
Showing
7 changed files
with
387 additions
and
758 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,15 @@ | ||
# 0.1.5 | ||
|
||
- Remove dependency on terraform in go.mod | ||
|
||
# 0.1.4 | ||
|
||
- Fix empty YAML crash (#21) | ||
|
||
# 0.1.3 | ||
|
||
- Ignore empty documents | ||
|
||
# 0.1.2 | ||
|
||
- Add heredoc syntax for multiline strings (#14) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
// NOTE this file was lifted verbatim from internal/repl in the terraform project | ||
// because the FormatValue function became internal in v1.0.0 | ||
|
||
package terraform | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/zclconf/go-cty/cty" | ||
) | ||
|
||
// FormatValue formats a value in a way that resembles Terraform language syntax | ||
// and uses the type conversion functions where necessary to indicate exactly | ||
// what type it is given, so that equality test failures can be quickly | ||
// understood. | ||
func FormatValue(v cty.Value, indent int) string { | ||
if !v.IsKnown() { | ||
return "(known after apply)" | ||
} | ||
if v.IsMarked() { | ||
return "(sensitive)" | ||
} | ||
if v.IsNull() { | ||
ty := v.Type() | ||
switch { | ||
case ty == cty.DynamicPseudoType: | ||
return "null" | ||
case ty == cty.String: | ||
return "tostring(null)" | ||
case ty == cty.Number: | ||
return "tonumber(null)" | ||
case ty == cty.Bool: | ||
return "tobool(null)" | ||
case ty.IsListType(): | ||
return fmt.Sprintf("tolist(null) /* of %s */", ty.ElementType().FriendlyName()) | ||
case ty.IsSetType(): | ||
return fmt.Sprintf("toset(null) /* of %s */", ty.ElementType().FriendlyName()) | ||
case ty.IsMapType(): | ||
return fmt.Sprintf("tomap(null) /* of %s */", ty.ElementType().FriendlyName()) | ||
default: | ||
return fmt.Sprintf("null /* %s */", ty.FriendlyName()) | ||
} | ||
} | ||
|
||
ty := v.Type() | ||
switch { | ||
case ty.IsPrimitiveType(): | ||
switch ty { | ||
case cty.String: | ||
if formatted, isMultiline := formatMultilineString(v, indent); isMultiline { | ||
return formatted | ||
} | ||
return strconv.Quote(v.AsString()) | ||
case cty.Number: | ||
bf := v.AsBigFloat() | ||
return bf.Text('f', -1) | ||
case cty.Bool: | ||
if v.True() { | ||
return "true" | ||
} else { | ||
return "false" | ||
} | ||
} | ||
case ty.IsObjectType(): | ||
return formatMappingValue(v, indent) | ||
case ty.IsTupleType(): | ||
return formatSequenceValue(v, indent) | ||
case ty.IsListType(): | ||
return fmt.Sprintf("tolist(%s)", formatSequenceValue(v, indent)) | ||
case ty.IsSetType(): | ||
return fmt.Sprintf("toset(%s)", formatSequenceValue(v, indent)) | ||
case ty.IsMapType(): | ||
return fmt.Sprintf("tomap(%s)", formatMappingValue(v, indent)) | ||
} | ||
|
||
// Should never get here because there are no other types | ||
return fmt.Sprintf("%#v", v) | ||
} | ||
|
||
func formatMultilineString(v cty.Value, indent int) (string, bool) { | ||
str := v.AsString() | ||
lines := strings.Split(str, "\n") | ||
if len(lines) < 2 { | ||
return "", false | ||
} | ||
|
||
// If the value is indented, we use the indented form of heredoc for readability. | ||
operator := "<<" | ||
if indent > 0 { | ||
operator = "<<-" | ||
} | ||
|
||
// Default delimiter is "End Of Text" by convention | ||
delimiter := "EOT" | ||
|
||
OUTER: | ||
for { | ||
// Check if any of the lines are in conflict with the delimiter. The | ||
// parser allows leading and trailing whitespace, so we must remove it | ||
// before comparison. | ||
for _, line := range lines { | ||
// If the delimiter matches a line, extend it and start again | ||
if strings.TrimSpace(line) == delimiter { | ||
delimiter = delimiter + "_" | ||
continue OUTER | ||
} | ||
} | ||
|
||
// None of the lines match the delimiter, so we're ready | ||
break | ||
} | ||
|
||
// Write the heredoc, with indentation as appropriate. | ||
var buf strings.Builder | ||
|
||
buf.WriteString(operator) | ||
buf.WriteString(delimiter) | ||
for _, line := range lines { | ||
buf.WriteByte('\n') | ||
buf.WriteString(strings.Repeat(" ", indent)) | ||
buf.WriteString(line) | ||
} | ||
buf.WriteByte('\n') | ||
buf.WriteString(strings.Repeat(" ", indent)) | ||
buf.WriteString(delimiter) | ||
|
||
return buf.String(), true | ||
} | ||
|
||
func formatMappingValue(v cty.Value, indent int) string { | ||
var buf strings.Builder | ||
count := 0 | ||
buf.WriteByte('{') | ||
indent += 2 | ||
for it := v.ElementIterator(); it.Next(); { | ||
count++ | ||
k, v := it.Element() | ||
buf.WriteByte('\n') | ||
buf.WriteString(strings.Repeat(" ", indent)) | ||
buf.WriteString(FormatValue(k, indent)) | ||
buf.WriteString(" = ") | ||
buf.WriteString(FormatValue(v, indent)) | ||
} | ||
indent -= 2 | ||
if count > 0 { | ||
buf.WriteByte('\n') | ||
buf.WriteString(strings.Repeat(" ", indent)) | ||
} | ||
buf.WriteByte('}') | ||
return buf.String() | ||
} | ||
|
||
func formatSequenceValue(v cty.Value, indent int) string { | ||
var buf strings.Builder | ||
count := 0 | ||
buf.WriteByte('[') | ||
indent += 2 | ||
for it := v.ElementIterator(); it.Next(); { | ||
count++ | ||
_, v := it.Element() | ||
buf.WriteByte('\n') | ||
buf.WriteString(strings.Repeat(" ", indent)) | ||
buf.WriteString(FormatValue(v, indent)) | ||
buf.WriteByte(',') | ||
} | ||
indent -= 2 | ||
if count > 0 { | ||
buf.WriteByte('\n') | ||
buf.WriteString(strings.Repeat(" ", indent)) | ||
} | ||
buf.WriteByte(']') | ||
return buf.String() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
// NOTE this file was lifted verbatim from internal/repl in the terraform project | ||
// because the FormatValue function became internal in v1.0.0 | ||
|
||
package terraform | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/zclconf/go-cty/cty" | ||
) | ||
|
||
func TestFormatValue(t *testing.T) { | ||
tests := []struct { | ||
Val cty.Value | ||
Want string | ||
}{ | ||
{ | ||
cty.NullVal(cty.DynamicPseudoType), | ||
`null`, | ||
}, | ||
{ | ||
cty.NullVal(cty.String), | ||
`tostring(null)`, | ||
}, | ||
{ | ||
cty.NullVal(cty.Number), | ||
`tonumber(null)`, | ||
}, | ||
{ | ||
cty.NullVal(cty.Bool), | ||
`tobool(null)`, | ||
}, | ||
{ | ||
cty.NullVal(cty.List(cty.String)), | ||
`tolist(null) /* of string */`, | ||
}, | ||
{ | ||
cty.NullVal(cty.Set(cty.Number)), | ||
`toset(null) /* of number */`, | ||
}, | ||
{ | ||
cty.NullVal(cty.Map(cty.Bool)), | ||
`tomap(null) /* of bool */`, | ||
}, | ||
{ | ||
cty.NullVal(cty.Object(map[string]cty.Type{"a": cty.Bool})), | ||
`null /* object */`, // Ideally this would display the full object type, including its attributes | ||
}, | ||
{ | ||
cty.UnknownVal(cty.DynamicPseudoType), | ||
`(known after apply)`, | ||
}, | ||
{ | ||
cty.StringVal(""), | ||
`""`, | ||
}, | ||
{ | ||
cty.StringVal("hello"), | ||
`"hello"`, | ||
}, | ||
{ | ||
cty.StringVal("hello\nworld"), | ||
`<<EOT | ||
hello | ||
world | ||
EOT`, | ||
}, | ||
{ | ||
cty.StringVal("EOR\nEOS\nEOT\nEOU"), | ||
`<<EOT_ | ||
EOR | ||
EOS | ||
EOT | ||
EOU | ||
EOT_`, | ||
}, | ||
{ | ||
cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("boop\nbeep")}), | ||
`{ | ||
"foo" = <<-EOT | ||
boop | ||
beep | ||
EOT | ||
}`, | ||
}, | ||
{ | ||
cty.Zero, | ||
`0`, | ||
}, | ||
{ | ||
cty.NumberIntVal(5), | ||
`5`, | ||
}, | ||
{ | ||
cty.NumberIntVal(1234567890), | ||
`1234567890`, | ||
}, | ||
{ | ||
cty.NumberFloatVal(5.2), | ||
`5.2`, | ||
}, | ||
{ | ||
cty.NumberFloatVal(123456789.0), | ||
`123456789`, | ||
}, | ||
{ | ||
cty.NumberFloatVal(123456789.01), | ||
`123456789.01`, | ||
}, | ||
{ | ||
cty.False, | ||
`false`, | ||
}, | ||
{ | ||
cty.True, | ||
`true`, | ||
}, | ||
{ | ||
cty.EmptyObjectVal, | ||
`{}`, | ||
}, | ||
{ | ||
cty.ObjectVal(map[string]cty.Value{ | ||
"a": cty.StringVal("b"), | ||
}), | ||
`{ | ||
"a" = "b" | ||
}`, | ||
}, | ||
{ | ||
cty.ObjectVal(map[string]cty.Value{ | ||
"a": cty.StringVal("b"), | ||
"c": cty.StringVal("d"), | ||
}), | ||
`{ | ||
"a" = "b" | ||
"c" = "d" | ||
}`, | ||
}, | ||
{ | ||
cty.MapValEmpty(cty.String), | ||
`tomap({})`, | ||
}, | ||
{ | ||
cty.EmptyTupleVal, | ||
`[]`, | ||
}, | ||
{ | ||
cty.TupleVal([]cty.Value{ | ||
cty.StringVal("b"), | ||
}), | ||
`[ | ||
"b", | ||
]`, | ||
}, | ||
{ | ||
cty.TupleVal([]cty.Value{ | ||
cty.StringVal("b"), | ||
cty.StringVal("d"), | ||
}), | ||
`[ | ||
"b", | ||
"d", | ||
]`, | ||
}, | ||
{ | ||
cty.ListValEmpty(cty.String), | ||
`tolist([])`, | ||
}, | ||
{ | ||
cty.SetValEmpty(cty.String), | ||
`toset([])`, | ||
}, | ||
{ | ||
cty.StringVal("sensitive value").Mark("sensitive"), | ||
"(sensitive)", | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(fmt.Sprintf("%#v", test.Val), func(t *testing.T) { | ||
got := FormatValue(test.Val, 0) | ||
if got != test.Want { | ||
t.Errorf("wrong result\nvalue: %#v\ngot: %s\nwant: %s", test.Val, got, test.Want) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.