cfg

package module
v0.0.0-...-4134304 Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2016 License: MIT Imports: 10 Imported by: 1

README

Build Status Coverage Godoc license Go Report Card

cfg

Simple read/write and commentable config files for go

Configuring

Package cfg implements a flat key value configuration that is read/writeable.

The format is simple and contains support for comments. The purpose is to be a simple format that is easily read/modified by both humans and computers.

Comments are only modifiable by humans, but are readable for computers.

Marshalling

The package also contains functionality to encode/decode (marshal and unmarshal) data to structs defined in go. The object's default key string is the struct field name but can be specified in the struct field's tag value. The "cfg" key in the struct field's tag value is the key name. Use "-" to skip the field. Like in the encoding/json package.

Examples

Config example
# This is a comment

# An integer value
answer = 42

# A float value
pi = 3.14

# A boolean value
is_active = true

# A string value
quotes = Alea iacta est\nEt tu, Brute?
Usage example

There are more examples defined in the example_test.go file. And you can easily view them in the documentation http://godoc.org/github.com/walle/cfg#pkg-examples

// Using the example config above
f, _ := os.Open("example.cfg")
config, err := cfg.NewConfigFromReader(f)
if err != nil {
        // Could not parse config
}
quotes, err := config.GetString("quotes")
if err != nil {
        // Could not find the key quotes
}
fmt.Println(quotes)
// Output:
// Alea iacta est
// Et tu, Brute?

Why?

There are many good libraries for reading configurations, but none (that I know of) that allows the user to update values in the config file. Go have really good support for JSON and JSON-files can be used for configuration. But they have a drawback, and that is that they cannot be commented (easily).

This library fixes this by having config files with comment support that also can be updated from code.

The format

The config file format is line based. Any line can be empty, contain a comment or contain a key value pair.

  • A comment is any line that starts with the character # excluding whitespace
  • A configuration option is any line in the format key = value
  • All other lines are empty

The format has support for four different types of values. integers, floats, booleans and strings. Integers are defined in decimal base. Floats are defined without exponents e.g. 3.14 not 3.14E+00. Booleans are defined as the string representation "true" or "false". Strings are defined as is with all new lines escaped to only take up one line.

The parser skips all whitespace, so whitespace before or after data is discarded. The key value, or configuration options can have as many whitespace characters before, after or in between the key value as desired. The following examples are all valid, and the foo[2-6]? keys all contain just "foo bar"

foo=foo bar
foo2= foo bar
foo3 =foo bar
foo4           =                   foo bar
foo5 = foo bar
    foo6 = foo bar

String values that contain line breaks have the line breaks escaped with the \n character. The config handles the escaping and unescapes the values when they are accessed.

Heads up

String configuration values are read exactly as they are written, with the exception of line breaks that are encoded to keep the value on the same line.

From issue #2 "Most other "INI-like" formats strip quotes from the front and back of strings".

This is not the case in cfg, if you have the value "foo" you get the value "foo" when you use the value in code.

Installation

To install cfg, just use go get.

$ go get github.com/walle/cfg

To start using it import the package.

import "github.com/walle/cfg"

Testing

Run the tests using go test.

$ go test -cover

Contributing

All contributions are welcome! See CONTRIBUTING for more info.

License

The code is under the MIT license. See LICENSE for more information.

Authors

The code is written by Fredrik Wallgren - https://github.com/walle

Documentation

Overview

Package cfg implements a flat key value configuration that is read/writeable The format is simple and contains support for comments. The purpose is to be a simple format that is easily read/modified by both humans and computers. Comments are only modifiable by humans, but are readable for computers. The format is line based and all configurations are defined on their own line. The format has support for four different types of values. integers, floats, booleans and strings. Integers are defined in decimal base. Floats are defined without exponents e.g. 3.14 not 3.14E+00. Booleans are defined as the string representation "true" or "false". Strings are defined as is with all new lines escaped to only take up one line.

Example configuration

# This is a comment

# An integer value
answer = 42

# A float value
pi = 3.14

# A boolean value
is_active = true

# A string value
quotes = Alea iacta est\nEt tu, Brute?

The package also contains functionality to encode/decode (marshal and unmarshal) data to structs defined in go. The object's default key string is the struct field name but can be specified in the struct field's tag value. The "cfg" key in the struct field's tag value is the key name. Use "-" to skip the field. Like in the encoding/json package.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Marshal

func Marshal(v interface{}) ([]byte, error)

Marshal returns the config encoding of v. v must be a pointer to a struct.

Struct values encode as config values. Each exported struct field becomes a member of the object unless

  • the field's tag is "-"

Only top level values of the supported types are encoded. No recursion down the struct is done.

The object's default key string is the struct field name but can be specified in the struct field's tag value. The "cfg" key in the struct field's tag value is the key name. Examples:

// Field is ignored by this package.
Field int `cfg:"-"`

// Field appears in config as key "myName".
Field int `cfg:"myName"`
Example
package main

import (
	"fmt"

	"github.com/walle/cfg"
)

func main() {
	type MyConfig struct {
		Answer     int
		Pi         float64
		IsActive   bool   `cfg:"is_active"`
		Quotes     string `cfg:"quotes"`
		unexported string
		NotUsed    string `cfg:"-"`
	}

	var myConfig = &MyConfig{
		Answer:     42,
		Pi:         3.14,
		IsActive:   true,
		Quotes:     "Alea iacta est\nEt tu, Brute?",
		unexported: "foo",
		NotUsed:    "bar",
	}

	data, err := cfg.Marshal(myConfig)
	if err != nil {
		// Handle error
	}

	fmt.Printf("%s", data)
}
Output:

Answer = 42
Pi = 3.14
is_active = true
quotes = Alea iacta est\nEt tu, Brute?

func Unmarshal

func Unmarshal(data []byte, v interface{}) error

Unmarshal parses the config data and stores the result in the value pointed to by v. v must be a pointer to a struct.

Unmarshal matches incoming keys to either the struct field name or its tag, preferring an exact match but also accepting a case-insensitive match. Only exported fields can be populated. The tag value "-" is used to skip a field.

If the type indicated in the struct field does not match the type in the config the field is skipped. Eg. the field type is int but contains a non numerical string value in the config data.

Example
package main

import (
	"fmt"

	"github.com/walle/cfg"
)

func main() {
	type MyConfig struct {
		Answer     int
		Pi         float64
		IsActive   bool   `cfg:"is_active"`
		Quotes     string `cfg:"quotes"`
		unexported string
		NotUsed    string `cfg:"-"`
	}

	const configString = `
# This is a comment

# An integer value
answer = 42

# A float value
pi = 3.14
# A boolean value
is_active = true

# A string value
quotes = Alea iacta est\nEt tu, Brute?
`

	myConfig := &MyConfig{}
	err := cfg.Unmarshal([]byte(configString), myConfig)
	if err != nil {
		// Handle error
	}

	fmt.Println(myConfig.Answer)
	fmt.Println(myConfig.Pi)
	fmt.Println(myConfig.IsActive)
	fmt.Println(myConfig.Quotes)

}
Output:

42
3.14
true
Alea iacta est
Et tu, Brute?

func UnmarshalFromConfig

func UnmarshalFromConfig(c *Config, v interface{}) error

UnmarshalFromConfig strores the data in config in the value pointed to by v. v must be a pointer to a struct.

UnmarshalFromConfig matches incoming keys to either the struct field name or its tag, preferring an exact match but also accepting a case-insensitive match. Only exported fields can be populated. The tag value "-" is used to skip a field.

If the type indicated in the struct field does not match the type in the config the field is skipped. Eg. the field type is int but contains a non numerical string value in the config data.

Types

type Config

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

Config implements access to configuration values.

func MarshalToConfig

func MarshalToConfig(v interface{}) (*Config, error)

MarshalToConfig creates a config object from the marshaled data in v. v must be a pointer to a struct.

Struct values encode as config values. Each exported struct field becomes a member of the object unless

  • the field's tag is "-"

Only top level values of the supported types are encoded. No recursion down the struct is done.

The object's default key string is the struct field name but can be specified in the struct field's tag value. The "cfg" key in the struct field's tag value is the key name. Examples:

// Field is ignored by this package.
Field int `cfg:"-"`

// Field appears in config as key "myName".
Field int `cfg:"myName"`

func NewConfig

func NewConfig() *Config

NewConfig creates a new empty configuration.

func NewConfigFromReader

func NewConfigFromReader(r io.Reader) (*Config, error)

NewConfigFromReader creates a new empty config and populates it with data parsed from the reader. If a error occurs when parsing the input an error is returned.

Example
package main

import (
	"bytes"
	"fmt"

	"github.com/walle/cfg"
)

func main() {
	const configString = `
# This is a comment

# An integer value
answer = 42

# A float value
pi = 3.14
# A boolean value
is_active = true

# A string value
quotes = Alea iacta est\nEt tu, Brute?
`

	r := bytes.NewBufferString(configString)
	config, err := cfg.NewConfigFromReader(r)
	if err != nil {
		// Handle error
	}

	a, _ := config.GetInt("answer")
	fmt.Println(a)
	p, _ := config.GetFloat("pi")
	fmt.Println(p)
	i, _ := config.GetBool("is_active")
	fmt.Println(i)
	q, _ := config.GetString("quotes")
	fmt.Println(q)

}
Output:

42
3.14
true
Alea iacta est
Et tu, Brute?

func (*Config) Comments

func (c *Config) Comments() []string

Comments returns all parsed comments in the config as a list of strings. Comments can not be modified programatically, but can be read. The comments are in the order they are defined in the source config.

func (*Config) GetBool

func (c *Config) GetBool(key string) (bool, error)

GetBool returns the value for key as a bool. If the key is not found an error is returned. If the value can not be represented as a boolean an error is returned.

func (*Config) GetFloat

func (c *Config) GetFloat(key string) (float64, error)

GetFloat returns the value for key as a float64. If the key is not found an error is returned. If the value can not be represented as a float an error is returned.

func (*Config) GetInt

func (c *Config) GetInt(key string) (int, error)

GetInt returns the value for key as an int in decimal base. If the key is not found an error is returned. If the value can not be represented as an integer an error is returned.

func (*Config) GetString

func (c *Config) GetString(key string) (string, error)

GetString returns the value for key as a string with new lines unescaped. If the key is not found an error is returned.

func (*Config) SetBool

func (c *Config) SetBool(key string, value bool)

SetBool creates or updates a value attached to key. The bool value is formated as "true" or "false".

func (*Config) SetFloat

func (c *Config) SetFloat(key string, value float64)

SetFloat creates or updates a value attached to key. The float value is formated without exponents eg. 3.14 not 3.14E+00.

func (*Config) SetInt

func (c *Config) SetInt(key string, value int)

SetInt creates or updates a value attached to key. All integer values are formated in decimal base.

func (*Config) SetString

func (c *Config) SetString(key, value string)

SetString creates or updates a value attached to key. Any new lines in the value are escaped.

func (*Config) String

func (c *Config) String() string

String returns a string representation of the config. All comments and values are present. Whitespaces are preserved as they were in the source that were parsed if any.

func (*Config) Unset

func (c *Config) Unset(key string)

Unset deletes a value from the config. Any comments defined in the source are preserved.

type ConfigFile

type ConfigFile struct {
	*Config
	// contains filtered or unexported fields
}

ConfigFile is a utility type that can load and save config to a file.

func NewConfigFile

func NewConfigFile(path string) (*ConfigFile, error)

NewConfigFile returns a new ConfigFile with the parsed data in the file at path. Returns an error if the file can't be read or if the parsing of the config fails.

func (*ConfigFile) Path

func (c *ConfigFile) Path() string

Path returns the path to the file with the config.

func (*ConfigFile) Persist

func (c *ConfigFile) Persist() error

Persist saves all configured values to the file. Returns error if something goes wrong.

Jump to

Keyboard shortcuts

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