hashicorp / hcl

HCL is the HashiCorp configuration language.
Mozilla Public License 2.0
5.26k stars 590 forks source link

Read HCL file without evaluation. #585

Open kamilpi opened 1 year ago

kamilpi commented 1 year ago

Hello,

I want to read terraform/terragrunt configuration files, store them inside of my stricture in golang test and use them for any purpose like generating new files with a different configuration, and do the validation if this file suits the current version of tests.

Right now when I try to read the HCL file when there is something like a "merge" function(terraform) I receive an error like this:

Function calls not allowed; Functions may not be called here.

Is there any way to read the such file without evaluation?

mlund01 commented 1 year ago

Hi @normander,

First, the reason for the error you received is probably due to having a nil EvalContext when you are decoding your config. You can read more on that here, but importantly, if you want to be able to evaluate those functions, you will need to provide them in the EvalContext yourself. If you are wondering where to find these functions, check out cty stdlib functions

Second, to answer your question on reading a file without evaluation - yes, you can decode your hcl config into Native Go values without evaluation. You can do so by utilizing hcl.Expression or hcl.Body types in your Go struct definitions. For example,

type Data struct {
    Name   string `hcl:"name,label"`
    Field1 hcl.Expression `hcl:"field1,attr"`
    Remain hcl.Body `hcl:",remain"`
}

When you decode your config, the resulting Data variable will have Field1 stored as an unevaluated expression, of which you can evaluate later with methods on hcl.Expression. The Remain field will store "everything else" from your config that wasn't defined explicitly in the struct, and can be decoded in a separate step into a different struct at a later time.

Note that a common approach when needing to leave certain fields unevaluated is to accomplish it in a stepped fashion. Start by defining a struct with "just enough" of the fields you absolutely need to decode into primitive go values, leave the rest as hcl.Expression (for fields you want to define explicitly in the step but leave unevaluated) and hcl.Body as a Remain field (note how the hcl tag is defined. That's important) for all the config values you will worry about later.

Here is a good answer to a similar question on decoding but not evaluating config until later... https://github.com/hashicorp/hcl/issues/496#issuecomment-983906130

catdevman commented 1 year ago

@kamilpi did you get the answer you're looking for?