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:
Megan Marsh 2021-03-22 02:56:30 -07:00 committed by GitHub
parent 1e312ebc21
commit 0993c976fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 107 additions and 2 deletions

View File

@ -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)
}

View File

@ -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 {

View File

@ -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")}"]
}
}

View File

@ -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\"}}"
]
}
]
}