| // Package hclsimple is a higher-level entry point for loading HCL |
| // configuration files directly into Go struct values in a single step. |
| // |
| // This package is more opinionated than the rest of the HCL API. See the |
| // documentation for function Decode for more information. |
| package hclsimple |
| |
| import ( |
| "fmt" |
| "io/ioutil" |
| "os" |
| "path/filepath" |
| "strings" |
| |
| "github.com/hashicorp/hcl/v2" |
| "github.com/hashicorp/hcl/v2/gohcl" |
| "github.com/hashicorp/hcl/v2/hclsyntax" |
| "github.com/hashicorp/hcl/v2/json" |
| ) |
| |
| // Decode parses, decodes, and evaluates expressions in the given HCL source |
| // code, in a single step. |
| // |
| // The main HCL API is built to allow applications that need to decompose |
| // the processing steps into a pipeline, with different tasks done by |
| // different parts of the program: parsing the source code into an abstract |
| // representation, analysing the block structure, evaluating expressions, |
| // and then extracting the results into a form consumable by the rest of |
| // the program. |
| // |
| // This function does all of those steps in one call, going directly from |
| // source code to a populated Go struct value. |
| // |
| // The "filename" and "src" arguments describe the input configuration. The |
| // filename is used to add source location context to any returned error |
| // messages and its suffix will choose one of the two supported syntaxes: |
| // ".hcl" for native syntax, and ".json" for HCL JSON. The src must therefore |
| // contain a sequence of bytes that is valid for the selected syntax. |
| // |
| // The "ctx" argument provides variables and functions for use during |
| // expression evaluation. Applications that need no variables nor functions |
| // can just pass nil. |
| // |
| // The "target" argument must be a pointer to a value of a struct type, |
| // with struct tags as defined by the sibling package "gohcl". |
| // |
| // The return type is error but any non-nil error is guaranteed to be |
| // type-assertable to hcl.Diagnostics for applications that wish to access |
| // the full error details. |
| // |
| // This is a very opinionated function that is intended to serve the needs of |
| // applications that are just using HCL for simple configuration and don't |
| // need detailed control over the decoding process. Because this function is |
| // just wrapping functionality elsewhere, if it doesn't meet your needs then |
| // please consider copying it into your program and adapting it as needed. |
| func Decode(filename string, src []byte, ctx *hcl.EvalContext, target interface{}) error { |
| var file *hcl.File |
| var diags hcl.Diagnostics |
| |
| switch suffix := strings.ToLower(filepath.Ext(filename)); suffix { |
| case ".hcl": |
| file, diags = hclsyntax.ParseConfig(src, filename, hcl.Pos{Line: 1, Column: 1}) |
| case ".json": |
| file, diags = json.Parse(src, filename) |
| default: |
| diags = diags.Append(&hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "Unsupported file format", |
| Detail: fmt.Sprintf("Cannot read from %s: unrecognized file format suffix %q.", filename, suffix), |
| }) |
| return diags |
| } |
| if diags.HasErrors() { |
| return diags |
| } |
| |
| diags = gohcl.DecodeBody(file.Body, ctx, target) |
| if diags.HasErrors() { |
| return diags |
| } |
| return nil |
| } |
| |
| // DecodeFile is a wrapper around Decode that first reads the given filename |
| // from disk. See the Decode documentation for more information. |
| func DecodeFile(filename string, ctx *hcl.EvalContext, target interface{}) error { |
| src, err := ioutil.ReadFile(filename) |
| if err != nil { |
| if os.IsNotExist(err) { |
| return hcl.Diagnostics{ |
| { |
| Severity: hcl.DiagError, |
| Summary: "Configuration file not found", |
| Detail: fmt.Sprintf("The configuration file %s does not exist.", filename), |
| }, |
| } |
| } |
| return hcl.Diagnostics{ |
| { |
| Severity: hcl.DiagError, |
| Summary: "Failed to read configuration", |
| Detail: fmt.Sprintf("Can't read %s: %s.", filename, err), |
| }, |
| } |
| } |
| |
| return Decode(filename, src, ctx, target) |
| } |