configs/configupgrade: Upgrade expressions nested in HCL list/object
In the old world, lists and maps could be created either using functions in HIL or list/object constructs in HCL. Here we ensure that in the HCL case we'll apply any required expression transformations to the individual items within HCL's compound constructs.
This commit is contained in:
parent
e49d993d89
commit
8cf024d45a
|
@ -0,0 +1,18 @@
|
||||||
|
locals {
|
||||||
|
in_map = {
|
||||||
|
foo = "${var.baz}"
|
||||||
|
}
|
||||||
|
in_list = [
|
||||||
|
"${var.baz}",
|
||||||
|
"${var.bar}",
|
||||||
|
]
|
||||||
|
in_list_oneline = ["${var.baz}", "${var.bar}"]
|
||||||
|
in_map_of_list = {
|
||||||
|
foo = ["${var.baz}"]
|
||||||
|
}
|
||||||
|
in_list_of_map = [
|
||||||
|
{
|
||||||
|
foo = "${var.baz}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
locals {
|
||||||
|
in_map = {
|
||||||
|
foo = var.baz
|
||||||
|
}
|
||||||
|
in_list = [
|
||||||
|
var.baz,
|
||||||
|
var.bar,
|
||||||
|
]
|
||||||
|
in_list_oneline = [var.baz, var.bar]
|
||||||
|
in_map_of_list = {
|
||||||
|
foo = [var.baz]
|
||||||
|
}
|
||||||
|
in_list_of_map = [
|
||||||
|
{
|
||||||
|
foo = var.baz
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
terraform {
|
||||||
|
required_version = ">= 0.12"
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package configupgrade
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
hcl2 "github.com/hashicorp/hcl2/hcl"
|
hcl2 "github.com/hashicorp/hcl2/hcl"
|
||||||
|
@ -28,8 +29,11 @@ func upgradeExpr(val interface{}, filename string, interp bool, an *analysis) ([
|
||||||
switch tv := val.(type) {
|
switch tv := val.(type) {
|
||||||
|
|
||||||
case *hcl1ast.LiteralType:
|
case *hcl1ast.LiteralType:
|
||||||
litVal := tv.Token.Value()
|
return upgradeExpr(tv.Token, filename, interp, an)
|
||||||
switch tv.Token.Type {
|
|
||||||
|
case hcl1token.Token:
|
||||||
|
litVal := tv.Value()
|
||||||
|
switch tv.Type {
|
||||||
case hcl1token.STRING:
|
case hcl1token.STRING:
|
||||||
if !interp {
|
if !interp {
|
||||||
// Easy case, then.
|
// Easy case, then.
|
||||||
|
@ -43,7 +47,7 @@ func upgradeExpr(val interface{}, filename string, interp bool, an *analysis) ([
|
||||||
Severity: hcl2.DiagError,
|
Severity: hcl2.DiagError,
|
||||||
Summary: "Invalid interpolated string",
|
Summary: "Invalid interpolated string",
|
||||||
Detail: fmt.Sprintf("Interpolation parsing failed: %s", err),
|
Detail: fmt.Sprintf("Interpolation parsing failed: %s", err),
|
||||||
Subject: hcl1PosRange(filename, tv.Pos()).Ptr(),
|
Subject: hcl1PosRange(filename, tv.Pos).Ptr(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,16 +68,58 @@ func upgradeExpr(val interface{}, filename string, interp bool, an *analysis) ([
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// For everything else (NUMBER, FLOAT) we'll just pass through the given bytes verbatim.
|
// For everything else (NUMBER, FLOAT) we'll just pass through the given bytes verbatim.
|
||||||
buf.WriteString(tv.Token.Text)
|
buf.WriteString(tv.Text)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case *hcl1ast.ListType:
|
||||||
|
multiline := tv.Lbrack.Line != tv.Rbrack.Line
|
||||||
|
buf.WriteString("[")
|
||||||
|
if multiline {
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
for i, node := range tv.List {
|
||||||
|
src, moreDiags := upgradeExpr(node, filename, interp, an)
|
||||||
|
diags = diags.Append(moreDiags)
|
||||||
|
buf.Write(src)
|
||||||
|
if multiline {
|
||||||
|
buf.WriteString(",\n")
|
||||||
|
} else if i < len(tv.List)-1 {
|
||||||
|
buf.WriteString(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.WriteString("]")
|
||||||
|
|
||||||
|
case *hcl1ast.ObjectType:
|
||||||
|
buf.WriteString("{\n")
|
||||||
|
for _, item := range tv.List.Items {
|
||||||
|
if len(item.Keys) != 1 {
|
||||||
|
diags = diags.Append(&hcl2.Diagnostic{
|
||||||
|
Severity: hcl2.DiagError,
|
||||||
|
Summary: "Invalid map element",
|
||||||
|
Detail: "A map element may not have any block-style labels.",
|
||||||
|
Subject: hcl1PosRange(filename, item.Pos()).Ptr(),
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
keySrc, moreDiags := upgradeExpr(item.Keys[0].Token, filename, interp, an)
|
||||||
|
diags = diags.Append(moreDiags)
|
||||||
|
valueSrc, moreDiags := upgradeExpr(item.Val, filename, interp, an)
|
||||||
|
diags = diags.Append(moreDiags)
|
||||||
|
buf.Write(keySrc)
|
||||||
|
buf.WriteString(" = ")
|
||||||
|
buf.Write(valueSrc)
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
buf.WriteString("}")
|
||||||
|
|
||||||
case hcl1ast.Node:
|
case hcl1ast.Node:
|
||||||
// If our more-specific cases above didn't match this then we'll
|
// If our more-specific cases above didn't match this then we'll
|
||||||
// ask the hcl1printer package to print the expression out
|
// ask the hcl1printer package to print the expression out
|
||||||
// itself, and assume it'll still be valid in HCL2.
|
// itself, and assume it'll still be valid in HCL2.
|
||||||
// (We should rarely end up here, since our cases above should
|
// (We should rarely end up here, since our cases above should
|
||||||
// be comprehensive.)
|
// be comprehensive.)
|
||||||
|
log.Printf("[TRACE] configupgrade: Don't know how to upgrade %T as expression, so just passing it through as-is", tv)
|
||||||
hcl1printer.Fprint(&buf, tv)
|
hcl1printer.Fprint(&buf, tv)
|
||||||
|
|
||||||
case *hilast.LiteralNode:
|
case *hilast.LiteralNode:
|
||||||
|
|
Loading…
Reference in New Issue