github.com/AlphaOne1/templig

Configuration files with templating support


License
MPL-2.0
Install
go get github.com/AlphaOne1/templig

Documentation

Logo
Test Pipeline Result CodeQL Pipeline Result Security Pipeline Result Go Report Card Code Coverage OpenSSF Best Practises OpenSSF Scorecard FOSSA Status FOSSA Status GoDoc Reference

templig

templig (pronounced [ˈtɛmplɪç]) is configuration library utilizing the text templating engine and the functions best known from helm charts, that originally stem from Masterminds/sprig. Its primary goal is to enable access to the system environment to fill information using the env function. It also enables to include verifications inside the configuration.

Usage

Simple Case

Having a configuration file like the following:

id:   23
name: Interesting Name

The code to read that file would look like this:

package main

import (
	"fmt"

	"github.com/AlphaOne1/templig"
)

type Config struct {
	ID   int    `yaml:"id"`
	Name string `yaml:"name"`
}

func main() {
	c, confErr := templig.FromFile[Config]("my_config.yaml")

	fmt.Printf("read errors: %v", confErr)

	if confErr == nil {
		fmt.Printf("ID:   %v\n", c.Get().ID)
		fmt.Printf("Name: %v\n", c.Get().Name)
	}
}

The Get method gives a pointer to the internally held Config structure that the use supplied. The pinter is always non-nil, so additional nil-checks are not necessary.

Reading environment

Having a templated configuration file like this one:

id:   23
name: Interesting Name
pass: {{ env "PASSWORD" | required "password required" | quote }}

or this one;

id:   23
name: Interesting Name
pass: {{ read "pass.txt" | required "password required" | quote }}

As demonstrated, one can use the templating functionality that is best known from helm charts. The functions provided come from the aforementioned sprig-library. For convenience templig also provides further functionality:

Function Description
required checks that its second argument is not zero length or nil
read reads the content of a file
package main

import (
	"fmt"
	"strings"

	"github.com/AlphaOne1/templig"
)

type Config struct {
	ID   int    `yaml:"id"`
	Name string `yaml:"name"`
	Pass string `yaml:"pass"`
}

func main() {
	c, confErr := templig.FromFile[Config]("my_config.yaml")

	fmt.Printf("read errors: %v", confErr)

	if confErr == nil {
		fmt.Printf("ID:   %v\n", c.Get().ID)
		fmt.Printf("Name: %v\n", c.Get().Name)
		fmt.Printf("Pass: %v\n", strings.Repeat("*", len(c.Get().Pass)))
	}
}

Validation

The templating facilities allow also for a wide range of tests, but depend on the configuration file read. As it is most like user supplied, possible consistency checks are not reliable in the form of template code. For this purpose, templig also allows for the configuration structure to implement the Validator interface. Implementing types provide a function Validate that allows templig to check after the configuration was read, if its structure could be considered valid and report errors accordingly.

package main

import (
    "errors"
    "fmt"

	"github.com/AlphaOne1/templig"
)

type Config struct {
    ID   int    `yaml:"id"`
    Name string `yaml:"name"`
}

// Validate fulfills the Validator interface provided by templig.
// This method is called, if it is defined. It influences the outcome of the configuration reading.
func (c *Config) Validate() error {
    result := make([]error, 0)

	if len(c.Name) == 0 {
		result = append(result, errors.New("name is required"))
	}

	if c.ID < 0 {
		result = append(result, errors.New("id greater than zero is required"))
	}

	return errors.Join(result...)
}

func main() {
	c, confErr := templig.FromFile[Config]("my_config_good.yaml")

	if confErr == nil {
		fmt.Printf("ID:   %v\n", c.Get().ID)
		fmt.Printf("Name: %v\n", c.Get().Name)
	}
}

Validation functionality can be as simple as in this example. But as the complexity of the configuration grows, automated tools to generate the configuration structure and basic consistency checks could be employed. These use JSON Schema or its embedded form in OpenAPI 2 or 3.

A non-exhaustive list of these: