struct2env

package module
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Nov 21, 2023 License: Apache-2.0 Imports: 8 Imported by: 1

README

struct2env

Convert between go structures to environment variables and back (for structured config <-> shell env and to kubernetes YAML env pod spec)

There are many go packages that are doing environment to go struct config (for instance https://github.com/kelseyhightower/envconfig) but I didn't find one doing the inverse and we needed to set a bunch of environment variables for shell and other tools to get some configuration structured as JSON and Go object, so this was born. For symmetry the reverse was also added.

A bit later the ToYamlWithPrefix() was also added as alternative serialization to insert in kubernetes deployment CI templates a common cluster configuration for instance.

Standalone package with 0 dependencies outside of the go standard library. Developed with go 1.20 but tested with go as old as 1.17 but should works with pretty much any go version, as it only depends on reflection and strconv.

The unit test has a fairly extensive example on how:

type FooConfig struct {
	Foo          string
	Bar          string
	Blah         int `env:"A_SPECIAL_BLAH"`
	ABool        bool
	NotThere     int `env:"-"`
	HTTPServer   string
	IntPointer   *int
	FloatPointer *float64
    // ...
}

Turns into (from the unit tests)

TST_FOO='a newline:
foo with $X, ` + "`backticks`" + `, " quotes and \ and '\'' in middle and end '\'''
TST_BAR='42str'
TST_A_SPECIAL_BLAH='42'
TST_A_BOOL=true
TST_HTTP_SERVER='http://localhost:8080'
TST_INT_POINTER='199'
TST_FLOAT_POINTER=
TST_INNER_A='inner a'
TST_INNER_B='inner b'
TST_RECURSE_HERE_INNER_A='rec a'
TST_RECURSE_HERE_INNER_B='rec b'
TST_SOME_BINARY='AAEC'
TST_DUR=3600.1
TST_TS='1998-11-05T14:30:00Z'
export TST_FOO TST_BAR TST_A_SPECIAL_BLAH TST_A_BOOL TST_HTTP_SERVER TST_INT_POINTER TST_FLOAT_POINTER TST_INNER_A TST_INNER_B TST_RECURSE_HERE_INNER_A TST_RECURSE_HERE_INNER_B TST_SOME_BINARY TST_DUR TST_TS

Using

kv, errs := struct2env.StructToEnvVars(foo)
txt := struct2env.ToShellWithPrefix("TST_", kv)

Or

  - name: Y_FOO
    value: "a newline:\nfoo with $X, `backticks`, \" quotes and \\ and ' in middle and end '"
  - name: Y_BAR
    value: "42str"
  - name: Y_A_SPECIAL_BLAH
    value: "42"
  - name: Y_A_BOOL
    value: true
  - name: Y_HTTP_SERVER
    value: "http://localhost:8080"
  - name: Y_INT_POINTER
    value: "199"
  - name: Y_FLOAT_POINTER
    value: null
  - name: Y_INNER_A
    value: "inner a"
  - name: Y_INNER_B
    value: "inner b"
  - name: Y_RECURSE_HERE_INNER_A
    value: "rec a"
  - name: Y_RECURSE_HERE_INNER_B
    value: "rec b"
  - name: Y_SOME_BINARY
    value: 'AAEC'
  - name: Y_DUR
    value: 3600.1
  - name: Y_TS
    value: "1998-11-05T14:30:00Z"

using

kv, errs := struct2env.StructToEnvVars(foo)
txt := struct2env.ToYamlWithPrefix("Y_", kv)

Type conversions:

  • Most primitive type to their string representation, single quote (') escaped for shell and double quote (") for YAML.
  • []byte are encoded as base64
  • time.Time are formatted as RFC3339
  • time.Duration are in (floating point) seconds.

Documentation

Overview

Package env provides conversion from structure to and from environment variables.

Supports converting struct fields to environment variables using field tags, handling most data types. Provides functions to serialize structs into slices of key-value pairs where the keys are derived from struct field names transformed to upper snake case by default, or specified explicitly via struct field tags.

Includes functionality to deserialize environment variables back into struct fields, handling pointers and nested structs appropriately, as well as providing shell-compatible output for environment variable definitions.

Incidentally the package also defines several case conversion functions that aid in manipulating which is useful for generating or parsing environment variables, JSON tags, or command line flags style of naming (camelCase, UPPER_SNAKE_CASE, lower-kebab-case ...)

The package leverages reflection to dynamically handle arbitrary struct types, and has 0 dependencies.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CamelCaseToLowerKebabCase

func CamelCaseToLowerKebabCase(s string) string

CamelCaseToLowerKebabCase converts a string from camelCase or CamelCase to lower-kebab-case. Handles cases like HTTPServer -> http-server. Good for command line flags for instance.

func CamelCaseToLowerSnakeCase

func CamelCaseToLowerSnakeCase(s string) string

CamelCaseToLowerSnakeCase converts a string from camelCase or CamelCase to lowe_snake_case. Handles cases like HTTPServer -> http_server. Good for JSON tags for instance.

func CamelCaseToUpperSnakeCase

func CamelCaseToUpperSnakeCase(s string) string

CamelCaseToUpperSnakeCase converts a string from camelCase or CamelCase to UPPER_SNAKE_CASE. Handles cases like HTTPServer -> HTTP_SERVER and httpServer -> HTTP_SERVER. Good for environment variables.

func SerializeValue

func SerializeValue(result *KeyValue, value interface{}) error

func SetFrom added in v0.2.0

func SetFrom(envLookup EnvLookup, prefix string, s interface{}) []error

Reverse of StructToEnvVars, assumes the same encoding. Using passed it lookup object that can lookup values by keys.

func SetFromEnv

func SetFromEnv(prefix string, s interface{}) []error

Reverse of StructToEnvVars, assumes the same encoding. Using the current os environment variables as source.

func ShellQuote added in v0.1.1

func ShellQuote(input string) (string, error)

Escape characters such as the result string can be embedded as a single argument in a shell fragment e.g for ENV_VAR=<value> such as <value> is safe (no $(cmd...) no ` etc`). Will error out if NUL is found in the input (use []byte for that and it'll get base64 encoded/decoded).

func SplitByCase

func SplitByCase(input string) []string

Split strings into words, using CamelCase/camelCase/CAMELCase rules.

func ToShell

func ToShell(kvl []KeyValue) string

func ToShellWithPrefix

func ToShellWithPrefix(prefix string, kvl []KeyValue, skipExport bool) string

This convert the key value pairs to bourne shell syntax (vs newer bash export FOO=bar). If skipExport is true the last line export VAR1 VAR2... is omitted.

func ToYamlWithPrefix added in v0.3.0

func ToYamlWithPrefix(indent int, prefix string, kvl []KeyValue) string

func YamlQuote added in v0.3.0

func YamlQuote(input string) string

Types

type EnvLookup added in v0.2.0

type EnvLookup func(key string) (string, bool)

type KeyValue

type KeyValue struct {
	Key            string // Must be safe (is when coming from Go struct names but could be bad with env:).
	ShellQuotedVal string // (Must be) Already quoted/escaped (” style).
	YamlQuotedVal  string // (Must be) Already quoted/escaped for yaml ("" with \ style).
}

Intermediate result list from StructToEnvVars(), both the Key and QuotedValue must be shell safe/non adversarial as they are emitted as is by String() with = in between. Using StructToEnvVars produces safe values even with adversarial input (length and future reoccurence of bugs like https://en.wikipedia.org/wiki/Shellshock_(software_bug) notwithstanding) So avoid or scrub external values if possible (or use []byte type which base64 encodes the values).

func StructToEnvVars

func StructToEnvVars(s interface{}) ([]KeyValue, []error)

StructToEnvVars converts a struct to a map of environment variables. The struct can have a `env` tag on each field. The tag should be in the format `env:"ENV_VAR_NAME"`. The tag can also be `env:"-"` to exclude the field from the map. If the field is exportable and the tag is missing we'll use the field name converted to UPPER_SNAKE_CASE (using CamelCaseToUpperSnakeCase()) as the environment variable name. []byte are encoded as base64, time.Time are formatted as RFC3339, time.Duration are in (floating point) seconds.

func (KeyValue) ToShell added in v0.3.0

func (kv KeyValue) ToShell() string

Jump to

Keyboard shortcuts

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