kv

package
v2.0.0-beta.1 Latest Latest
Warning

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

Go to latest
Published: Jun 3, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package kv is for working with key-value pair files and strings often found in configuration files, environment variables, and other sources.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidTags is returned when the struct tags are invalid for kv.
	ErrInvalidTags = errors.New("invalid tags")

	// ErrInvalidObject is returned when the object is invalid to be a kv decoding target.
	ErrInvalidObject = errors.New("invalid object")

	// ErrStrict is returned when the decoder is in strict mode and an unknown key is encountered.
	ErrStrict = errors.New("strict mode")
)
View Source
var (

	// ErrSyntax is returned when the input string has a syntactical error.
	ErrSyntax = errors.New("syntax error")
)

Functions

func Split

func Split(s string) (key string, value string, err error)

Split is a convenience function that calls SplitRune with '=' as the separator.

func SplitRune

func SplitRune(s string, separator rune) (key string, value string, err error)

SplitRune splits a string into a key and a value using the given separator. Quotes and escape characters are parsed in a similar manner to a shell. The separator is not included in the key or value. If the input string has a syntax error such as mismatched quotes or no delimiter, the error will be of type kv.ErrSyntax.

Example
package main

import (
	"fmt"

	"github.com/k0sproject/rig/v2/kv"
)

func main() {
	key, value, _ := kv.SplitRune(`key="value in quotes"`, '=')
	fmt.Println("key:", key)
	fmt.Println("value:", value)
}
Output:
key: key
value: value in quotes

Types

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

Decoder is a decoder for key-value pairs, similar to the encoding/json package. You can use struct tags to customize the decoding process.

The tag format is:

Field type `kv:"key_name,option1,option2"`.

The key_name is the key in the key-value pair.

  • If the key is empty, the field name is used.
  • If the key is '-', the field is ignored.
  • If the key is '*' and the field is a map[string]string, it will catch all the keys that are not matched by the other tags.

The options are:

  • ignorecase: the key is matched case-insensitively
  • delim: when the field is a slice, the value is split by the specified delimiter. Default is ','.

Given a struct like this:

type Config struct {
  Host string `kv:"host"`
  Port  int `kv:"port"`
  Enabled bool `kv:"enabled"`
  Options []string `kv:"options,delim=|"`
  Extra map[string]string `kv:"*"`
}

And having data like this in config.txt:

host=10.0.0.1
port=8080
enabled=true
options=opt1|opt2|opt3
hostname=example.com

Once decoded, you will get the Config fields set like this:

  • Host: "10.0.0.1" (string)
  • Port: 8080 (int)
  • Enabled: true (bool). The values parsed as "true" for booleans are: "1", "true", "TRUE", "True", "on", "ON", "On", "yes", "YES", "Yes", "y" and "Y"
  • Options: []string{"opt1", "opt2", "opt3"}
  • Extra: map[string]string{"hostname": "example.com"}
Example
package main

import (
	"fmt"
	"strings"

	"github.com/k0sproject/rig/v2/kv"
)

func main() {
	type testStruct struct {
		Key1     string            `kv:"key1"`
		Key2     int               `kv:"key2"`
		Key3     []string          `kv:"key3,delim:/"`
		CatchAll map[string]string `kv:"*"`
	}
	target := testStruct{}
	data := "key1=value1\nkey2=42\nkey3=foo/bar\nexample=example-catch-all"
	decoder := kv.NewDecoder(strings.NewReader(data))
	err := decoder.Decode(&target)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("* Input data:")
	fmt.Println(data)
	fmt.Println()
	fmt.Println("String value:", target.Key1)
	fmt.Println("Int value:", target.Key2)
	fmt.Println("Slice of strings:", target.Key3)
	fmt.Println("Catch all:", target.CatchAll["example"])

}
Output:
* Input data:
key1=value1
key2=42
key3=foo/bar
example=example-catch-all

String value: value1
Int value: 42
Slice of strings: [foo bar]
Catch all: example-catch-all

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder returns a new decoder that reads from r.

func (*Decoder) CommentStart

func (d *Decoder) CommentStart(comment string)

CommentStart sets the comment start string. If a line starts with the comment start string, it is ignored.

func (*Decoder) Decode

func (d *Decoder) Decode(obj any) (err error)

Decode reads all of the key-value pairs from the input and stores them in the map or struct pointed to by obj.

func (*Decoder) FieldDelimiter

func (d *Decoder) FieldDelimiter(delim rune)

FieldDelimiter sets the field delimiter. The default is '='.

func (*Decoder) RowDelimiter

func (d *Decoder) RowDelimiter(delim byte)

RowDelimiter sets the row delimiter. The default is '\n'.

func (*Decoder) Strict

func (d *Decoder) Strict()

Strict makes the decoder return an error when an unknown key or an assign error is encountered.

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

Encoder writes key-value pairs to an output stream. The field delimiter defaults to '=' and the row delimiter to '\n'.

Struct fields are encoded using the same kv struct tags as Decoder:

Field type `kv:"key_name,option1,option2"`

Tag options:

  • omitempty: skip the field when its value is the zero value
  • delim=X: for slice fields, join elements with delimiter X (default ',')
  • '-': skip the field entirely
  • '*': encode a map[string]string field as additional key-value pairs

Keys and values that contain the field delimiter, quotes, backslashes, leading/trailing whitespace, or keys that start with the comment prefix (default "#") are automatically double-quoted with backslash escaping. Keys or values containing the row delimiter cannot be encoded and cause an error. Note: slice elements that themselves contain the slice delimiter or leading/trailing whitespace cannot be round-tripped through the Decoder.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/k0sproject/rig/v2/kv"
)

func main() {
	type Config struct {
		Host    string   `kv:"host"`
		Port    int      `kv:"port"`
		Tags    []string `kv:"tags,delim:/"`
		Comment string   `kv:"-"`
	}
	cfg := Config{Host: "localhost", Port: 9000, Tags: []string{"a", "b"}, Comment: "ignored"}
	var buf strings.Builder
	if err := kv.NewEncoder(&buf).Encode(cfg); err != nil {
		panic(err)
	}
	fmt.Print(buf.String())
}
Output:
host=localhost
port=9000
tags=a/b

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder returns a new Encoder that writes to w.

func (*Encoder) CommentStart

func (e *Encoder) CommentStart(s string)

CommentStart sets the comment prefix. Keys starting with this prefix are automatically quoted so they are not mistaken for comments by Decoder. Default is "#" to match Decoder's default.

func (*Encoder) Encode

func (e *Encoder) Encode(obj any) error

Encode writes the key-value representation of obj to the stream. obj may be a map with string-convertible keys, or a struct (or pointer to struct).

func (*Encoder) FieldDelimiter

func (e *Encoder) FieldDelimiter(delim rune)

FieldDelimiter sets the field delimiter. Default is '='.

func (*Encoder) RowDelimiter

func (e *Encoder) RowDelimiter(delim byte)

RowDelimiter sets the row delimiter. Default is newline.

Jump to

Keyboard shortcuts

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