virtuald/pyhcl

heredoc handling

Closed this issue · 6 comments

is there a reason that the contents of heredoc blocks are loaded as a single string instead of as json? If a single line is added at the bottom of the _end_heredoc() method like this:

t.value = json.loads(t.value)

the contents of the heredoc will be accessible as a dictionary like the rest of the document.

Could you give an example of an HCL file that shows what you mean?

Sorry, can't seem to get it to show as code..

resource "aws_iam_user_policy" "lb_ro" {
  name = "test"
  user = "someUser"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "ec2:Describe*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
EOF
}

Currently it returns as:

'aws_iam_user_policy': {'lb_ro': {'name': 'test', 'user': 'someUser', 'policy': '{\n  "Version": "2012-10-17",\n  "Statement": [\n    {\n      "Action": [\n        "ec2:Describe*"\n      ],\n      "Effect": "Allow",\n      "Resource": "*"\n    }\n  ]\n}'}}

I would like it to return as:

'aws_iam_user_policy': {'lb_ro': {'name': 'test', 'user': 'someUser', 'policy': {'Version': '2012-10-17', 'Statement': [{'Action': ['ec2:Describe*'], 'Effect': 'Allow', 'Resource': '*'}]}}}

I see. Unfortunately I don't believe there is any requirement that heredocs must be in some JSON structure. For example, the official HCL repo has a test where the heredoc is not in a JSON structure: https://github.com/hashicorp/hcl/blob/master/test-fixtures/multiline.hcl

Therefore, this is something that would have to be done in post processing.

ok, small change; this allows it to work both ways

        try:
            t.value = json.loads(t.value)
        except:
            pass

HCL:

resource "aws_iam_user_policy" "badJson" {
name = "test"
user = "someUser"

policy = <<EOF
bar
baz
EOF
}

resource "aws_iam_user_policy" "goodJson" {
name = "test"
user = "someUser"

policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ec2:Describe*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
EOF
}

output showing both:
'aws_iam_user_policy': {'badJson': {'name': 'test', 'user': 'someUser', 'policy': 'bar\nbaz'}, 'goodJson': {'name': 'test', 'user': 'someUser', 'policy': {'Version': '2012-10-17', 'Statement': [{'Action': ['ec2:Describe*'], 'Effect': 'Allow', 'Resource': '*'}]}}}

Yes, that could be done, but it would be a breaking change for anyone that has a heredoc that is JSON-like but they expect it to be loaded as a string. Everything I have found regarding heredocs seems to indicate that the contents should be treated as a string and not implicitly converted to something else.

Agree. If you want the contents of the heredoc to not be a string, don't use a heredoc, use HCL structure instead.

Of course, this seems to be driven by a terraform use case. If someone were to create a library that specifically handled terraform files, then it might be appropriate in that library to do the transform you're asking for. However, pyhcl is just a HCL parser, and should not contain any terraform-specific hacks.