Fixes https://github.com/hashicorp/terraform/issues/6359 and several
related issues by unescaping a double backslash within braces to a
single backslash.
This bumps into the bit of HIL that still hangs out in HCL - for values
that aren't interpolated, like Terraform's variable defaults - users
were unable to get a backslash to show up within `${}`.
That's because `${}` is handled specially to allow for, e.g., double
quotes inside of braces.
Here, we add `\\` as a special cased escape (along with `\"`) so users
can get backslashes in these scenarios by doubling them up.
The fmtcmd tests weren't running before due to the same build tag
problem as #112, so didn't catch the fact that there was an extra
newline being added here, which is now doubled thanks to #112.
Fixing up the build tag reveals failing tests - removing the extra
newline fixes the tests.
Noticed that the `hclfmt` tool (which uses hcl/printer) was chomping
the trailing newline from config files.
Here we switch to the more conventional newline-at-EOF output.
In the process of changing this, I realized that:
* The printer_test.go build tag was wrong, so it wasn't running
* The format() test helper was not exercising Format
So both of those fixes are included here
This commit adds support for removing a hanging indent from HEREDOC
token contents if the marker is prefixed with <<-. For example, given
the HCL definition:
my_long_var_name = <<-EOF
{
"key": "value"
}
EOF
The value of the HEREDOC will be:
{
"key": "value"
}
This is useful for use cases where indentation or leading whitespace
is important.
The rule applied is that the prefix on the terminating marker will be
removed from each each line in the HEREDOC, providing all the lines have
that prefix (i.e. every line is at least as indented as the terminating
marker, and using the same mechanism of tabs vs spaces).
This PR adds support for the style of HEREDOC often used in Ruby which
allows the terminating marker to be indented if the HEREDOC is started
with the sequence "<<-" rather than the usual "<<". This allows users to
express documents with more natural indentation:
resource "template_file" "test" {
template = <<-HEREDOC
First Line
Second Line
HEREDOC
}
Note that this does not attempt to add any semantics around removing
hanging indent from the actual text of the document, so extra
indentation would still be present. We could make use of the canonical
style for HCL herre to remove the hanging indent in the style of Ruby
which would probably be more predictable for users.
The red CI build on Windows is making it harder to process actual bugs -
neither printer or fmt are used in any HC projects currently so
ignoring the tests on AppVeyor/Windows seems reasonable for now. At some
point they need fixing to account for line endings.
This now gives an error instead of a panic when encountering
configuration such as described in hashicorp/terraform#5740:
```
resource "aws" "web" {
provider = "aws" {
region = "us-west-2"
}
}
```
We now return an error message - "hcl object keys must be a string"
instead of crashing.
Fixeshashicorp/terraform#5740.
This uses the `printer` package to normalise HCL files. It's inspired by
github.com/fatih/hclfmt - but it differs in that it's intended to be more
generic, re-usable, and follow the semantics of `gofmt` or `go fmt`.
I intend to utilise this in Terraform by implementing `terraform fmt`
sub-command which will normalise all files in the current working directory
(like `go fmt ./..`) or contents over STDIN (with `terraform fmt -` that
could be used by editor plugins). So that Terraform users can benefit from
linting without installing another package/binary.
I hope that by placing most of the logic in the HCL package it should be
easy to implement sub-commands in other projects that also use HCL.
Some notes about the implementation:
- the significant difference from `gofmt` is that STDIN/STDOUT are passed in
and errors aren't logged/written directly to STDERR, which gives consumers
(e.g. Terraform) the ability to set appropriate exit codes
- I chose to use inline fixtures instead of files because there were a
number of times where I needed to reference the contents and group them
together with diff output
- it seemed simplest to construct the expected outputs by looping over the
relevant fixtures and building up a string/byte slice, hope it isn't too
confusing to read
- the test failure reporting is kind of rough because the outputs are so
large, but I didn't want to add another diff function
- I chose to have a separate test for sub-directories rather than making it
the default in the fixtures so that I didn't need to add additional logic
to the fixture rendering
- the fixtures are sorted by filename before any of the tests runs so that
they match the order that they are read from disk by `filepath.Walk()`