hcl2_upgrade escaped quotes fix (#10794)
* clean up extra quoting that can cause text template failures. when everyone else abandons you, regex will always be there. * LINTING
This commit is contained in:
parent
1e312ebc21
commit
0993c976fa
|
@ -8,7 +8,9 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
texttemplate "text/template"
|
||||
|
||||
|
@ -437,7 +439,22 @@ func transposeTemplatingCalls(s []byte) []byte {
|
|||
Parse(string(s))
|
||||
|
||||
if err != nil {
|
||||
return fallbackReturn(err, s)
|
||||
if strings.Contains(err.Error(), "unexpected \"\\\\\" in operand") {
|
||||
// This error occurs if the operand in the text template used
|
||||
// escaped quoting \" instead of bactick quoting `
|
||||
// Create a regex to do a string replace on this block, to fix
|
||||
// quoting.
|
||||
q := fixQuoting(string(s))
|
||||
unquoted := []byte(q)
|
||||
tpl, err = texttemplate.New("hcl2_upgrade").
|
||||
Funcs(funcMap).
|
||||
Parse(string(unquoted))
|
||||
if err != nil {
|
||||
return fallbackReturn(err, unquoted)
|
||||
}
|
||||
} else {
|
||||
return fallbackReturn(err, s)
|
||||
}
|
||||
}
|
||||
|
||||
str := &bytes.Buffer{}
|
||||
|
@ -502,7 +519,22 @@ func variableTransposeTemplatingCalls(s []byte) (isLocal bool, body []byte) {
|
|||
Parse(string(s))
|
||||
|
||||
if err != nil {
|
||||
return isLocal, fallbackReturn(err, s)
|
||||
if strings.Contains(err.Error(), "unexpected \"\\\\\" in operand") {
|
||||
// This error occurs if the operand in the text template used
|
||||
// escaped quoting \" instead of bactick quoting `
|
||||
// Create a regex to do a string replace on this block, to fix
|
||||
// quoting.
|
||||
q := fixQuoting(string(s))
|
||||
unquoted := []byte(q)
|
||||
tpl, err = texttemplate.New("hcl2_upgrade").
|
||||
Funcs(funcMap).
|
||||
Parse(string(unquoted))
|
||||
if err != nil {
|
||||
return isLocal, fallbackReturn(err, unquoted)
|
||||
}
|
||||
} else {
|
||||
return isLocal, fallbackReturn(err, s)
|
||||
}
|
||||
}
|
||||
|
||||
str := &bytes.Buffer{}
|
||||
|
@ -1247,3 +1279,23 @@ var PASSTHROUGHS = map[string]string{"NVME_Present": "{{ .NVME_Present }}",
|
|||
"ProviderVagrantfile": "{{ .ProviderVagrantfile }}",
|
||||
"Sound_Present": "{{ .Sound_Present }}",
|
||||
}
|
||||
|
||||
func fixQuoting(old string) string {
|
||||
// This regex captures golang template functions that use escaped quotes:
|
||||
// {{ env \"myvar\" }}
|
||||
re := regexp.MustCompile(`{{\s*\w*\s*(\\".*\\")\s*}}`)
|
||||
|
||||
body := re.ReplaceAllFunc([]byte(old), func(s []byte) []byte {
|
||||
// Get the capture group
|
||||
group := re.ReplaceAllString(string(s), `$1`)
|
||||
|
||||
unquoted, err := strconv.Unquote(fmt.Sprintf("\"%s\"", group))
|
||||
if err != nil {
|
||||
return s
|
||||
}
|
||||
return []byte(strings.Replace(string(s), group, unquoted, 1))
|
||||
|
||||
})
|
||||
|
||||
return string(body)
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ func Test_hcl2_upgrade(t *testing.T) {
|
|||
{folder: "variables-only", flags: []string{}},
|
||||
{folder: "variables-with-variables", flags: []string{}},
|
||||
{folder: "complete-variables-with-template-engine", flags: []string{}},
|
||||
{folder: "escaping", flags: []string{}},
|
||||
}
|
||||
|
||||
for _, tc := range tc {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
variable "conf" {
|
||||
type = string
|
||||
default = "${env("ONE")}-${env("ANOTHER")}-${env("BACKTICKED")}"
|
||||
}
|
||||
|
||||
variable "manyspaces" {
|
||||
type = string
|
||||
default = "${env("ASDFASDF")}"
|
||||
}
|
||||
|
||||
variable "nospaces" {
|
||||
type = string
|
||||
default = "${env("SOMETHING")}"
|
||||
}
|
||||
|
||||
locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }
|
||||
# The "legacy_isotime" function has been provided for backwards compatability, but we recommend switching to the timestamp and formatdate functions.
|
||||
|
||||
source "null" "autogenerated_1" {
|
||||
communicator = "none"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.null.autogenerated_1"]
|
||||
|
||||
provisioner "shell-local" {
|
||||
inline = ["echo ${var.conf}-${local.timestamp}-${legacy_isotime("01-02-2006")}"]
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"variables": {
|
||||
"conf": "{{ env \"ONE\" }}-{{env \"ANOTHER\"}}-{{ env `BACKTICKED` }}",
|
||||
"nospaces": "{{env \"SOMETHING\"}}",
|
||||
"manyspaces": "{{ env \"ASDFASDF\"}}"
|
||||
},
|
||||
"builders": [
|
||||
{
|
||||
"type": "null",
|
||||
"communicator": "none"
|
||||
}
|
||||
],
|
||||
"provisioners": [
|
||||
{
|
||||
"type": "shell-local",
|
||||
"inline": [
|
||||
"echo {{user \"conf\"}}-{{timestamp}}-{{isotime \"01-02-2006\"}}"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue