confighcl

package module
v0.2.12 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 15, 2026 License: MIT Imports: 11 Imported by: 0

README

config-hcl

Read and write HCL configuration through config — HCL as a configuration format, not Terraform

Go Reference Pipeline Coverage phpboyscout Go toolkit

Part of the phpboyscout Go toolkit — small, framework-free Go modules extracted from go-tool-base. Documented with the parent module at config.go.phpboyscout.uk


config has one codec of its own, YAML, which also reads JSON because YAML 1.2 is a superset of it. Every other file format is a sibling module like this one.

import (
	"gitlab.com/phpboyscout/go/config"
	confighcl "gitlab.com/phpboyscout/go/config-hcl"
)

store, err := config.NewStore(ctx,
	config.WithFiles(fsys, "/etc/app.yaml"),                    // YAML, the default
	config.WithBackend(confighcl.New(fsys, "/etc/app.hcl")),    // outranks it
)

HCL as a configuration format, not Terraform

This module serves HCL the way Nomad, Consul, Vault, Packer and purpose-built HCL DSLs use it, and deliberately not Terraform. A document that reaches outside itself for a value — a var.* reference, ${local.x} interpolation, or a function call — is refused at load with config.ErrBackendUnsafe naming the construct, because there is no correct answer without a variable context a configuration library does not have and should not invent. Point it at a .tf file and it says so plainly, rather than computing a value from a half-context that looks right and is not.

Blocks and labels are path segments

A block's type and labels become dotted-key segments:

migration "multi_state" "move_redis" {
  enabled = true
}

reads as migration.multi_state.move_redis.enabled. Two blocks sharing a type and every label collide (an error, not last-one-wins), and repeated unlabelled blocks of one type are refused — they have no dotted-key representation.

Reading and writing

Because every document it accepts is expression-free, HCL here is exactly as safe to edit as YAML, and writing is HashiCorp's hclwrite — a targeted edit that preserves comments, block order and formatting, changing only the value asked for. Setting or removing a block attribute or a top-level attribute is supported; writing into a sub-path of an object-valued attribute, or creating a new nested block from a dotted path, is refused rather than guessed.

What it costs

This is the heaviest adapter: the config graph plus HashiCorp's HCL toolchain (hashicorp/hcl/v2, zclconf/go-cty) and what those bring. An allowlist test states the full set, so an unforeseen transitive addition fails the build. No filesystem library: you supply the config.FS.

License

See LICENSE.

Documentation

Overview

Package confighcl reads and writes HCL configuration through the config codec seam.

It serves HCL as a configuration format — Nomad, Consul, Vault, Packer, and purpose-built HCL DSLs — and deliberately not Terraform. A document that reaches outside itself for a value (a `var.*` reference, `${local.x}` interpolation, or a function call) is refused at load with config.ErrBackendUnsafe naming the construct, because there is no correct answer without a variable context a configuration library does not have and should not invent. Point it at a `.tf` file and it says so, rather than computing a value from a half-context that looks right and is not.

config.NewStore(ctx,
	config.WithFiles(fsys, "/etc/app.yaml"),        // YAML, the default
	config.WithBackend(confighcl.New(fsys, "/etc/app.hcl")),
)

Blocks and labels are path segments

A block's type and labels become dotted-key segments, so

migration "multi_state" "move_redis" { enabled = true }

reads as migration.multi_state.move_redis.enabled. An attribute reads by the path its enclosing blocks spell out.

Reading and writing

Because every document the adapter accepts is expression-free, it is exactly as safe to edit as YAML, and writing is HashiCorp's hclwrite — a targeted edit that preserves comments, block order and formatting, changing only the value asked for. Setting or removing a block attribute or a top-level attribute is supported; writing into a sub-path of an object-valued attribute, or creating a new nested block from a dotted path, is not, and is refused rather than guessed.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(filesystem config.FS, path string) config.Backend

New reads and writes an HCL document.

Types

type Codec added in v0.2.0

type Codec struct{}

Codec reads HCL into layer values and edits it in place. New uses it, and it is exported so a backend adapter can reuse it as a value decoder — a Consul or etcd key whose value is an HCL document, decoded into a subtree via that adapter's WithValueCodec option. It is a config.Codec (and config.EditingCodec).

Reading is hclparse's; editing is hclwrite's. The two never cross: decoded values feed the read side, and edits are applied to bytes, and every document the codec accepts is expression-free so the two cannot disagree about what a value is.

func (Codec) Apply added in v0.2.0

func (Codec) Apply(path string, src []byte, edits []config.Edit) ([]byte, error)

Apply folds the edits into the document with hclwrite, which changes the bytes for one attribute and leaves comments, block order and formatting alone.

func (Codec) Check added in v0.2.0

func (c Codec) Check(path string, src []byte) error

Check reports whether an HCL source can be edited safely, which for HCL is the same question as whether it reads: a document that decodes is expression-free, and expression-free HCL is exactly as safe to edit as YAML.

func (Codec) Decode added in v0.2.0

func (Codec) Decode(path string, src []byte) ([]map[string]any, error)

func (Codec) Empty added in v0.2.0

func (Codec) Empty() []byte

Empty returns the content of a new, empty HCL document.

func (Codec) PreservesComments added in v0.2.2

func (Codec) PreservesComments() bool

PreservesComments reports that HCL edits retain comments, block order and formatting — hclwrite changes only the bytes of the value asked for. It satisfies config.CommentPreservingCodec, the exported probe the store reads to surface the backend's PreservesComments capability truthfully.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL