unicon

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2020 License: MIT Imports: 13 Imported by: 0

README

Unicon

Unicon is a simple hierarchial config manager for Go lang. Inspired by nconf. Originally a fork from gonfig.

GitHub release (latest by date) GitHub Workflow Status (branch) PkgGoDev GitHub

Docs

Api

All the config types including the root implement the Configurable interface.

// The main Configurable interface
// Also the hierarcial configuration (Config) implements it.
type Configurable interface {
  // Get a configuration variable from config
  Get(string) string
  // Set a variable, nil to reset key
  Set(string, string)
  // Reset the config data to passed data, if nothing is given set it to zero value
  Reset(...map[string]string)
  // Return a map of all variables
  All() map[string]string
}

type WritebleConfig interface {
  ReadableConfig
  // Save configuration
  Save() error
}

type ReadableConfig interface {
  Configurable
  // Load the configuration
  Load() error
}

// The hierarchial Config that can be used to mount other configs that are searched for keys by Get
type Config struct {
  // Overrides, these are checked before Configs are iterated for key
  Configurable
  // named configurables, these are iterated if key is not found in Config
  Configs map[string]Configurable
  // Defaults configurable, if key is not found in the Configurable & Configurables in Config,
  //Defaults is checked for fallback values
  Defaults Configurable
}

Usage & Examples

For more examples check out example_test.go

  // Create a new root node for our hierarchical configuration
  conf := NewConfig(nil)

  // setting to the rootnode makes the variable found first, so it acts as an override for all the other
  // configurations set in the config.
  conf.Set("always", true);

  // use commandline variables myapp.*, ie --myapp-rules
  conf.Use("argv", NewNewArgvConfig("myapp.*"))

  // use env variables MYAPP_*
  conf.Use("env", NewEnvConfig("MYAPP_"))

  // load local config file
  conf.Use("local", NewJSONConfig("./config.json"))

  // load global config file over the network
  conf.Use("global", NewURLConfig("http://myapp.com/config/globals.json"))

  // Set some Defaults, if conf.Get() fails to find from any of the above configurations it will fall back to these.
  conf.Defaults.Reset(map[string]interface{}{
    "database": "127.0.0.1",
    "temp_dir":"/tmp",
    "always": false,
  })

  log.Println("Database host in network configuration",conf.Use("global").Get("database"))
  log.Println("Database host resolved from hierarchy",conf.Get("database"))

  // Save the hierarchy to a JSON file:
  jsonconf := NewJSONConf("./new_config.json")
  jsonconf.Reset(conf.All())
  if err := jsonconf.Save(); err != nil {
    log.Fatalln("Failed saving json config at path",jsonconf.Path,err)
  }
}

Extending

Extending Unicon is easy using the MemoryConfig or JSONConfig as a base, depending on the Save needs. Here is an example implementation using a file with line separated key=value pairs for storage.

type KVFileConfig struct {
  Configurable
  Path string
}

func NewKVFileConfig(path string) WritableConfig {
  return &KVFileConfig{NewMemoryConfig(), path}
}

func (self *KVFileConfig) Load() (err error) {
  var file *os.File

  if file, err = os.Open(self.Path); err != nil {
    return err
  }
  defer file.Close()

  scanner := bufio.NewScanner(file)
  for scanner.Scan() {
    fmt.Println(scanner.Text())
    parts := strings.Split(scanner.Text(), "=")
    if len(parts) == 2 {
      self.Set(parts[0], parts[1])
    }
  }
  return scanner.Err();
}

func (self *KVFileConfig) Save() (err error) {
  var file *os.File;
  if file, err = os.Create(self.Path); err != nil {
    return err
  }
  defer file.Close();
  for k, v := range self.All() {
    if _, err = file.WriteString(k + "=" + fmt.Sprint("",v) + "\r\n"); err != nil {
      return err
    }
  }
  return nil
}

License

The MIT License (MIT)

Copyright (c) 2016-2020 Taybin Rutkin
Copyright (c) 2013 Matti Savolainen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Documentation

Overview

Package unicon provides tools for managing hierarcial configuration from multiple sources

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func LoadConfig

func LoadConfig(config Configurable) error

LoadConfig loads a config if it is of type ReadableConfig, otherwise does nothing.

func SaveConfig

func SaveConfig(config Configurable) error

SaveConfig saves if is of type WritableConfig, otherwise does nothing.

Types

type ArgvConfig

type ArgvConfig struct {
	Configurable
	Prefix string
	// contains filtered or unexported fields
}

ArgvConfig is the Argv configurable.

func (*ArgvConfig) Load

func (ac *ArgvConfig) Load() (err error)

Load loads all the variables from argv to the underlaying Configurable. If a Prefix is provided for ArgvConfig then keys are imported with the Prefix removed so --test.asd=1 with Prefix 'test.' imports "asd" with value of 1

type Config

type Config interface {
	WritableConfig
	// Use config as name, .Use("name") without the second parameter returns
	// the config previously added to the hierarchy with the name.
	// Use("name", Configurable) adds or replaces the configurable designated
	// by "Name" in the hierarchy
	Use(name string, config ...Configurable) Configurable
}

Config is a Configurable that can Use other Configurables thus build a hierarchy

type Configurable

type Configurable interface {
	Get(string) interface{}
	GetString(key string) string
	GetBool(key string) bool
	GetInt(key string) int
	GetInt64(key string) int64
	GetFloat64(key string) float64
	GetTime(key string) time.Time
	GetDuration(key string) time.Duration

	// Set a variable, nil to reset key
	Set(string, interface{})
	// Overwrite items with items from map
	BulkSet(map[string]interface{})
	// Reset the config data to passed data, if nothing is given set it to zero
	// value
	Reset(...map[string]interface{})
	// Return a map of all variables
	All() map[string]interface{}
}

Configurable is the main interface. Also the hierarcial configuration (Config) implements it.

type EnvConfig

type EnvConfig struct {
	Configurable
	Prefix string
	// contains filtered or unexported fields
}

EnvConfig can be used to read values from the environment into the underlaying Configurable

func (*EnvConfig) Load

func (ec *EnvConfig) Load() (err error)

Load loads the data from os.Environ() to the underlaying Configurable. if a Prefix is set then variables are imported with self.Prefix removed from the name so MYAPP_test=1 exported in env and read from ENV by EnvConfig{Prefix:"MYAPP_"} can be found from EnvConfig.Get("test") If namespaces are declared, POSTGRESQL_HOST becomes postgresql.host

type FlagSetConfig

type FlagSetConfig struct {
	Configurable
	Prefix string
	// contains filtered or unexported fields
}

FlagSetConfig can be used to read arguments in the posix flag style into the underlaying Configurable

func (*FlagSetConfig) Load

func (fsc *FlagSetConfig) Load() (err error)

Load loads all the variables from argv to the underlaying Configurable. If a Prefix is provided for FlagSetConfig then keys are imported with the Prefix removed so --test.asd=1 with Prefix 'test.' imports "asd" with value of 1

type JSONConfig

type JSONConfig struct {
	Configurable
	Path string
}

JSONConfig is the json configurable

func NewJSONConfig

func NewJSONConfig(path string, cfg ...Configurable) *JSONConfig

NewJSONConfig returns a new WritableConfig backed by a json file at path. The file does not need to exist, if it does not exist the first Save call will create it.

func (*JSONConfig) Load

func (jc *JSONConfig) Load() (err error)

Load attempts to load the json configuration at JSONConfig.Path and Set them into the underlaying Configurable

func (*JSONConfig) Save

func (jc *JSONConfig) Save() (err error)

Save attempts to save the configuration from the underlaying Configurable to json file at JSONConfig.Path

type MemoryConfig

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

MemoryConfig is a simple abstraction to map[]interface{} for in process memory backed configuration only implements Configurable use JsonConfig to save/load if needed

func NewMemoryConfig

func NewMemoryConfig() *MemoryConfig

NewMemoryConfig returns a new memory backed Configurable The most basic Configurable simply backed by a map[string]interface{}

func (*MemoryConfig) All

func (mem *MemoryConfig) All() map[string]interface{}

All returns all keys

func (*MemoryConfig) BulkSet

func (mem *MemoryConfig) BulkSet(items map[string]interface{})

BulkSet overwrites the overrides with items in the provided map

func (*MemoryConfig) Get

func (mem *MemoryConfig) Get(key string) interface{}

Get key from map

func (*MemoryConfig) GetBool

func (mem *MemoryConfig) GetBool(key string) bool

GetBool casts the value as a bool. If value is nil, it returns false

func (*MemoryConfig) GetDuration

func (mem *MemoryConfig) GetDuration(key string) time.Duration

GetDuration casts the value as a time.Duration. If the value is nil, it returns the 0 duration

func (*MemoryConfig) GetFloat64

func (mem *MemoryConfig) GetFloat64(key string) float64

GetFloat64 casts the value as a float64. If the value is nil, it returns 0.0

func (*MemoryConfig) GetInt

func (mem *MemoryConfig) GetInt(key string) int

GetInt casts the value as an int. If the value is nil, it returns 0

func (*MemoryConfig) GetInt64

func (mem *MemoryConfig) GetInt64(key string) int64

GetInt64 casts the value as an int64. If the value is nil, it returns 0

func (*MemoryConfig) GetString

func (mem *MemoryConfig) GetString(key string) string

GetString casts the value as a string. If value is nil, it returns ""

func (*MemoryConfig) GetTime

func (mem *MemoryConfig) GetTime(key string) time.Time

GetTime casts the value as a time.Time. If the value is nil, it returns the 0 time

func (*MemoryConfig) Reset

func (mem *MemoryConfig) Reset(datas ...map[string]interface{})

Reset if no arguments are provided Reset() re-creates the underlaying map

func (*MemoryConfig) Set

func (mem *MemoryConfig) Set(key string, value interface{})

Set a key to value

type PflagConfig

type PflagConfig struct {
	Configurable
	Prefix string
	// contains filtered or unexported fields
}

PflagConfig can be used to read arguments in the posix flag style into the underlaying Configurable

func (*PflagConfig) Load

func (pc *PflagConfig) Load() (err error)

Load loads all the variables from argv to the underlaying Configurable. If a Prefix is provided for PflagConfig then keys are imported with the Prefix removed so --test.asd=1 with Prefix 'test.' imports "asd" with value of 1

type ReadableConfig

type ReadableConfig interface {
	Configurable
	// Load the configuration
	Load() error
}

ReadableConfig is a Configurable that can be loaded

func NewArgvConfig

func NewArgvConfig(prefix string, namespaces ...string) ReadableConfig

NewArgvConfig creates a new ArgvConfig and returns it as a ReadableConfig

func NewEnvConfig

func NewEnvConfig(prefix string, namespaces ...string) ReadableConfig

NewEnvConfig creates a new Env config backed by a memory config

func NewFlagSetConfig

func NewFlagSetConfig(fs *pflag.FlagSet, prefix string, namespaces ...string) ReadableConfig

NewFlagSetConfig creates a new FlagSetConfig and returns it as a ReadableConfig

func NewPflagConfig

func NewPflagConfig(prefix string, namespaces ...string) ReadableConfig

NewPflagConfig creates a new PflagConfig and returns it as a ReadableConfig

func NewURLConfig

func NewURLConfig(url string) ReadableConfig

NewURLConfig returns a new Configurable backed by JSON at url

type URLConfig

type URLConfig struct {
	Configurable
	// contains filtered or unexported fields
}

URLConfig is the url configurable

func (*URLConfig) Load

func (uc *URLConfig) Load() error

Load attempts to read a json file at a remote address

type Unicon

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

Unicon is the Hierarchical Config that can be used to mount other configs that are searched for keys by Get

func NewConfig

func NewConfig(initial Configurable, defaults ...Configurable) *Unicon

NewConfig creates a new config that is by default backed by a MemoryConfig Configurable. Takes optional initial configuration and an optional defaults

func (*Unicon) All

func (uni *Unicon) All() map[string]interface{}

All returns a map of data from all Configurables in use the first found instance of variable found is provided. Config.Use("a", NewMemoryConfig()). Config.Use("b", NewMemoryConfig()). Config.Use("a").Set("a","1"). Config.Set("b").Set("a","2"). then. Config.All()["a"] == "1". Config.Get("a") == "1". Config.Use("b".).Get("a") == "2".

func (*Unicon) BulkSet

func (uni *Unicon) BulkSet(items map[string]interface{})

BulkSet overwrites the overrides with items in the provided map

func (*Unicon) BulkSetDefault

func (uni *Unicon) BulkSetDefault(items map[string]interface{})

BulkSetDefault overwrites the defaults with items in the provided map

func (*Unicon) Debug

func (uni *Unicon) Debug()

Debug prints out simple list of keys as returned by All()

func (*Unicon) Get

func (uni *Unicon) Get(key string) interface{}

Get gets the key from first store that it is found from, checks defaults

func (*Unicon) GetBool

func (uni *Unicon) GetBool(key string) bool

GetBool casts the value as a bool. If value is nil, it returns false

func (*Unicon) GetDefault

func (uni *Unicon) GetDefault(key string) interface{}

GetDefault returns the default for the key, regardless of whether Set() has been called for that key or not.

func (*Unicon) GetDuration

func (uni *Unicon) GetDuration(key string) time.Duration

GetDuration casts the value as a time.Duration. If the value is nil, it returns the 0 duration

func (*Unicon) GetFloat64

func (uni *Unicon) GetFloat64(key string) float64

GetFloat64 casts the value as a float64. If the value is nil, it returns 0.0

func (*Unicon) GetInt

func (uni *Unicon) GetInt(key string) int

GetInt casts the value as an int. If the value is nil, it returns 0

func (*Unicon) GetInt64

func (uni *Unicon) GetInt64(key string) int64

GetInt64 casts the value as an int64. If the value is nil, it returns 0

func (*Unicon) GetString

func (uni *Unicon) GetString(key string) string

GetString casts the value as a string. If value is nil, it returns ""

func (*Unicon) GetTime

func (uni *Unicon) GetTime(key string) time.Time

GetTime casts the value as a time.Time. If the value is nil, it returns the 0 time

func (*Unicon) Load

func (uni *Unicon) Load() error

Load calls Configurable.Load() on all Configurable objects in the hierarchy.

func (*Unicon) Reset

func (uni *Unicon) Reset(datas ...map[string]interface{})

Reset resets all configs with the provided data, if no data is provided empties all stores. Never touches the Defaults, to reset Defaults use Unicon.ResetDefaults()

func (*Unicon) ResetDefaults

func (uni *Unicon) ResetDefaults(datas ...map[string]interface{})

ResetDefaults resets just the defaults with the provided data. Needed because Reset() doesn't reset the defaults.

func (*Unicon) Save

func (uni *Unicon) Save() error

Save saves all mounted configurations in the hierarchy that implement the WritableConfig interface

func (*Unicon) Set

func (uni *Unicon) Set(key string, value interface{})

Set sets a key to a particular value

func (*Unicon) SetDefault

func (uni *Unicon) SetDefault(key string, value interface{})

SetDefault sets the default value, which will be looked up if no other values match the key. The default is preserved across Set() and Reset() can can only be modified by SetDefault() or ResetDefaults()

func (*Unicon) Sub

func (uni *Unicon) Sub(ns string) *Unicon

Sub returns a new Unicon but with the namespace prepended to Gets/Sets/Subs behind the scenes

func (*Unicon) Unmarshal

func (uni *Unicon) Unmarshal(target interface{}) error

Unmarshal current configuration hierarchy into target using gonfig:

func (*Unicon) Use

func (uni *Unicon) Use(name string, config ...Configurable) Configurable

Use config as named config and return an already set and loaded config mounts a new configuration in the hierarchy. conf.Use("global", NewUrlConfig("http://host.com/config..json")). conf.Use("local", NewFileConfig("./config.json")) err := conf.Load();. Then get variable from specific config. conf.Use("global").Get("key"). or traverse the hierarchy and search for "key". conf.Get("key"). conf.Use("name") returns a nil value for non existing config named "name".

type WritableConfig

type WritableConfig interface {
	ReadableConfig
	// Save configuration
	Save() error
}

WritableConfig is a Configurable that can be Loaded & Saved

Jump to

Keyboard shortcuts

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