konfig: github.com/lalamove/konfig Index | Files | Directories

package konfig

import "github.com/lalamove/konfig"

Package konfig provides a composable, observable and performant config handling for Go. Written for larger distributed systems where you may have plenty of configuration sources - it allows you to compose configurations from multiple sources with reload hooks making it simple to build apps that live in a highly dynamic environment.

Konfig is built around 4 small interfaces: Loader, Watcher, Parser, Closer

Get started:

var configFiles = []klfile.File{
      {
          Path:   "./config.json",
          Parser: kpjson.Parser,
      },
}

func init() {
	konfig.Init(konfig.DefaultConfig())
}

func main() {
	// load from json file with a file wacher
	konfig.RegisterLoaderWatcher(
		klfile.New(&klfile.Config{
			Files: configFiles,
			Watch: true,
		}),
		// optionally you can pass config hooks to run when a file is changed
		func(c konfig.Store) error {
			return nil
		},
	)

    // Load and start watching
	if err := konfig.LoadWatch(); err != nil {
		log.Fatal(err)
	}

	// retrieve value from config file
	konfig.Bool("debug")
}

Index

Package Files

closers.go config.go getter.go group.go konfig.go loader.go loaderwatcher.go metrics.go util.go value.go values.go watcher.go

Constants

const (
    // TagKey is the tag key to unmarshal config values to bound value
    TagKey = "konfig"
    // KeySep is the separator for config keys
    KeySep = "."
)

Variables

var (
    // ErrInvalidConfigFileFormat is the error returned when a problem is encountered when parsing the
    // config file
    ErrInvalidConfigFileFormat = errors.New("Err invalid file format")

    // ErrLoaderNotFound is the error thrown when the loader with the given name cannot be found in the config store
    ErrLoaderNotFound = errors.New("Err loader not found")
    // ErrConfigNotFoundMsg is the error message thrown when a config key is not set
    ErrConfigNotFoundMsg = "Err config '%s' not found"
    // ErrStrictKeyNotFoundMsg is the error returned when a strict key is not found in the konfig store
    ErrStrictKeyNotFoundMsg = "Err strict key '%s' not found"
)
var (
    // MetricsConfigReload is the label for the prometheus counter for loader reload
    MetricsConfigReload = "konfig_loader_reload"
    // MetricsConfigReloadDuration is the label for the prometheus summary vector for loader reload duration
    MetricsConfigReloadDuration = "konfig_loader_reload_duration"
)
var (
    // ErrIncorrectValue is the error thrown when trying to bind an invalid type to a config store
    ErrIncorrectValue = errors.New("Bind takes a map[string]interface{} or a struct")
    // ErrIncorrectStructValue is the error thrown when trying to bind a non struct value with the BindStructStrict method
    ErrIncorrectStructValue = errors.New("BindStructStrict takes a struct")
)
var ErrNoLoaders = errors.New("No loaders in config")

ErrNoLoaders is the error returned when no loaders are set in the config and Load is called

func Bind Uses

func Bind(v interface{})

Bind binds a value to the root config store

func BindStructStrict Uses

func BindStructStrict(v interface{})

BindStructStrict binds a value to the root config store and adds the exposed keys as strict keys

func Bool Uses

func Bool(k string) bool

Bool gets the config k and converts it to a bool. It returns the zero value if it doesn't find the config.

func Duration Uses

func Duration(k string) time.Duration

Duration gets the config k and converts it to a duration. It returns the zero value if it doesn't find the config.

func Exists Uses

func Exists(k string) bool

Exists checks if a config key k is set in the Store

func Float Uses

func Float(k string) float64

Float gets the config k and tries to convert it to float64 It returns the zero value if it doesn't find the config.

func Get Uses

func Get(k string) interface{}

Get will return the value in config with given key k If not value is found, Get it returns nil

func Getter Uses

func Getter(k string) ngetter.GetterTyped

Getter returns a mgetter.Getter for the key k

func Init Uses

func Init(cfg *Config)

Init initiates the global config store with the given Config cfg

func Int Uses

func Int(k string) int

Int gets the config k and tries to convert it to an int It returns the zero value if it doesn't find the config.

func IntSlice Uses

func IntSlice(k string) []int

IntSlice gets the config k and converts it to a []int. it returns the zero value if it doesn't find the config.

func Load Uses

func Load() error

Load is a function running load on the global config instance

func LoadWatch Uses

func LoadWatch() error

LoadWatch loads the config then starts watching it

func MustBool Uses

func MustBool(k string) bool

MustBool gets the config k and tries to convert it to a bool it panics if it fails.

func MustDuration Uses

func MustDuration(k string) time.Duration

MustDuration gets the config k and tries to convert it to a duration it panics if it fails.

func MustFloat Uses

func MustFloat(k string) float64

MustFloat gets the config k and tries to convert it to a float64 it panics if it fails.

func MustGet Uses

func MustGet(k string) interface{}

MustGet returns the value in config with given key k If not found it panics

func MustInt Uses

func MustInt(k string) int

MustInt gets the config k and tries to convert it to an int it panics if the config does not exist or it fails to convert it to an int.

func MustIntSlice Uses

func MustIntSlice(k string) []int

MustIntSlice gets the config k and tries to convert it to a []int it panics if it fails.

func MustString Uses

func MustString(k string) string

MustString gets the config k and tries to convert it to a string it panics if it fails.

func MustStringMap Uses

func MustStringMap(k string) map[string]interface{}

MustStringMap gets the config k and tries to convert it to a map[string]interface{} it panics if it fails.

func MustStringMapString Uses

func MustStringMapString(k string) map[string]string

MustStringMapString gets the config k and tries to convert it to a map[string]string it panics if it fails.

func MustStringSlice Uses

func MustStringSlice(k string) []string

MustStringSlice gets the config k and tries to convert it to a []string it panics if it fails.

func MustTime Uses

func MustTime(k string) time.Time

MustTime gets the config k and tries to convert it to a time.Time it panics if it fails.

func RunHooks Uses

func RunHooks() error

RunHooks runs all hooks and child groups hooks

func Set Uses

func Set(k string, v interface{})

Set will set the key value to the sync.Map

func SetLogger Uses

func SetLogger(l nlogger.Structured)

SetLogger sets the logger used in the global store

func String Uses

func String(k string) string

String gets the config k and tries to convert it to a string It returns the zero value if it doesn't find the config.

func StringMap Uses

func StringMap(k string) map[string]interface{}

StringMap gets the config k and converts it to a map[string]interface{}. it returns the zero value if it doesn't find the config.

func StringMapString Uses

func StringMapString(k string) map[string]string

StringMapString gets the config k and converts it to a map[string]string. it returns the zero value if it doesn't find the config.

func StringSlice Uses

func StringSlice(k string) []string

StringSlice gets the config k and converts it to a []string. It returns the zero value if it doesn't find the config.

func Time Uses

func Time(k string) time.Time

Time gets the config k and converts it to a time.Time. It returns the zero value if it doesn't find the config.

func Value Uses

func Value() interface{}

Value returns the value bound to the root config store

func Watch Uses

func Watch() error

Watch starts the watchers on loaders

type Closers Uses

type Closers []io.Closer

Closers is a multi closer

func (Closers) Close Uses

func (cs Closers) Close() error

Close closes all closers in the multi closer and returns an error if an error was encountered. Error returned is multierror.Error. https://github.com/hashicorp/go-multierror

type Config Uses

type Config struct {
    // Name is the name of the config store, it is used in metrics as a label. When creating a config group, the name of the group becomes the name of the store
    Name string
    // ExitCode is the code to exit when errors are encountered in loaders
    ExitCode int
    // Disables exiting the program (os.Exit) when errors on loaders
    NoExitOnError bool
    // NoStopOnFailure if false the store closes all registered Watchers and Closers and exit the process unless NoExitOnError is true
    // when a Loader fails to load or a Loader Hook fails. If true, nothing happens when a Loader fails.
    NoStopOnFailure bool
    // Logger is the logger used internally
    Logger nlogger.Provider
    // Metrics sets whether a konfig.Store should record metrics for config loaders
    Metrics bool
    // MaxWatcherPanics is the maximum number of times to restart a watcher when it panics, default is 0.
    MaxWatcherPanics int
}

Config is the config to init a config store

func DefaultConfig Uses

func DefaultConfig() *Config

DefaultConfig returns a default Config

type ConfigLoader Uses

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

ConfigLoader is a wrapper of Loader with methods to add hooks

func RegisterLoader Uses

func RegisterLoader(l Loader, loaderHooks ...func(Store) error) *ConfigLoader

RegisterLoader registers a Loader l with a given Watcher w.

func RegisterLoaderWatcher Uses

func RegisterLoaderWatcher(lw LoaderWatcher, loaderHooks ...func(Store) error) *ConfigLoader

RegisterLoaderWatcher registers a WatcherLoader to the config.

func (*ConfigLoader) AddHooks Uses

func (cl *ConfigLoader) AddHooks(loaderHooks ...func(Store) error) *ConfigLoader

AddHooks adds hooks to the loader

type Loader Uses

type Loader interface {
    // StopOnFailure tells whether a loader failure should lead to closing config and the registered closers.
    StopOnFailure() bool
    // Name returns the name of the loader
    Name() string
    // Load loads config values in a Values
    Load(Values) error
    // MaxRetry returns the max number of times to retry when Load fails
    MaxRetry() int
    // RetryDelay returns the delay between each retry
    RetryDelay() time.Duration
}

Loader is the interface a config loader must implement to be used withint the package

type LoaderHooks Uses

type LoaderHooks []func(Store) error

LoaderHooks are functions ran when a config load has been performed

func (LoaderHooks) Run Uses

func (l LoaderHooks) Run(cfg Store) error

Run runs all loader and stops when it encounters an error

type LoaderWatcher Uses

type LoaderWatcher interface {
    Loader
    Watcher
}

LoaderWatcher is an interface that implements both loader and watcher

func NewLoaderWatcher Uses

func NewLoaderWatcher(l Loader, w Watcher) LoaderWatcher

NewLoaderWatcher creates a new LoaderWatcher from a Loader and a Watcher

type NopWatcher Uses

type NopWatcher struct{}

NopWatcher is a nil watcher

func (NopWatcher) Close Uses

func (NopWatcher) Close() error

Close is a noop that returns nil

func (NopWatcher) Done Uses

func (NopWatcher) Done() <-chan struct{}

Done returns an already closed channel

func (NopWatcher) Err Uses

func (NopWatcher) Err() error

Err returns nil, because nothing can go wrong when you do nothing

func (NopWatcher) Start Uses

func (NopWatcher) Start() error

Start implements watcher interface and always returns a nil error

func (NopWatcher) Watch Uses

func (NopWatcher) Watch() <-chan struct{}

Watch implements a basic watch that waits forever

type S Uses

type S struct {
    WatcherLoaders []*loaderWatcher
    WatcherClosers Closers
    Closers        Closers
    // contains filtered or unexported fields
}

S is the concrete implementation of the Store

func New Uses

func New(cfg *Config) *S

New returns a new Store with the given config

func (*S) Bind Uses

func (c *S) Bind(v interface{})

Bind binds a value (either a map[string]interface{} or a struct) to the config store. When config values are set on the config store, they are also set on the bound value.

func (*S) BindStructStrict Uses

func (c *S) BindStructStrict(v interface{})

BindStructStrict binds a value (must a struct) to the config store and adds the exposed fields as strick keys.

func (*S) Bool Uses

func (c *S) Bool(k string) bool

Bool gets the config k and converts it to a bool. It returns the zero value if it doesn't find the config.

func (*S) Duration Uses

func (c *S) Duration(k string) time.Duration

Duration gets the config k and converts it to a duration. It returns the zero value if it doesn't find the config.

func (*S) Exists Uses

func (c *S) Exists(k string) bool

Exists checks if a config key k is set in the Store

func (*S) Float Uses

func (c *S) Float(k string) float64

Float gets the config k and tries to convert it to float64 It returns the zero value if it doesn't find the config.

func (*S) Get Uses

func (c *S) Get(k string) interface{}

Get gets a value from config

func (*S) Getter Uses

func (c *S) Getter(k string) ngetter.GetterTyped

Getter returns a mgetter.Getter for the key k

func (*S) Group Uses

func (c *S) Group(groupName string) Store

Group gets a group of configs

func (*S) Int Uses

func (c *S) Int(k string) int

Int gets the config k and tries to convert it to an int It returns the zero value if it doesn't find the config.

func (*S) IntSlice Uses

func (c *S) IntSlice(k string) []int

IntSlice gets the config k and converts it to a []int. it returns the zero value if it doesn't find the config.

func (*S) Load Uses

func (c *S) Load() error

Load is a function running load on the global config instance

func (*S) LoadWatch Uses

func (c *S) LoadWatch() error

LoadWatch loads the config then starts watching it

func (*S) MustBool Uses

func (c *S) MustBool(k string) bool

MustBool gets the config k and tries to convert it to a bool it panics if it fails.

func (*S) MustDuration Uses

func (c *S) MustDuration(k string) time.Duration

MustDuration gets the config k and tries to convert it to a duration it panics if it fails.

func (*S) MustFloat Uses

func (c *S) MustFloat(k string) float64

MustFloat gets the config k and tries to convert it to a float64 it panics if it fails.

func (*S) MustGet Uses

func (c *S) MustGet(k string) interface{}

MustGet gets a value from config and panics if the value does not exist

func (*S) MustInt Uses

func (c *S) MustInt(k string) int

MustInt gets the config k and tries to convert it to an int it panics if the config does not exist or it fails to convert it to an int.

func (*S) MustIntSlice Uses

func (c *S) MustIntSlice(k string) []int

MustIntSlice gets the config k and tries to convert it to a []int it panics if it fails.

func (*S) MustString Uses

func (c *S) MustString(k string) string

MustString gets the config k and tries to convert it to a string it panics if it fails.

func (*S) MustStringMap Uses

func (c *S) MustStringMap(k string) map[string]interface{}

MustStringMap gets the config k and tries to convert it to a map[string]interface{} it panics if it fails.

func (*S) MustStringMapString Uses

func (c *S) MustStringMapString(k string) map[string]string

MustStringMapString gets the config k and tries to convert it to a map[string]string it panics if it fails.

func (*S) MustStringSlice Uses

func (c *S) MustStringSlice(k string) []string

MustStringSlice gets the config k and tries to convert it to a []string it panics if it fails.

func (*S) MustTime Uses

func (c *S) MustTime(k string) time.Time

MustTime gets the config k and tries to convert it to a time.Time it panics if it fails.

func (*S) Name Uses

func (c *S) Name() string

Name returns the name of the store. The name for the root store is "root".

func (*S) RegisterCloser Uses

func (c *S) RegisterCloser(closer io.Closer) Store

RegisterCloser adds a closer to the list of closers. Closers are closed when an error occurred while reloading a config and the ExitOnError config is set to true

func (*S) RegisterKeyHook Uses

func (c *S) RegisterKeyHook(k string, f func(Store) error) Store

RegisterKeyHook adds a hook to be run on the given key k and all subkeys of k

func (*S) RegisterLoader Uses

func (c *S) RegisterLoader(l Loader, loaderHooks ...func(Store) error) *ConfigLoader

RegisterLoader registers a Loader l with a given Watcher w.

func (*S) RegisterLoaderWatcher Uses

func (c *S) RegisterLoaderWatcher(lw LoaderWatcher, loaderHooks ...func(Store) error) *ConfigLoader

RegisterLoaderWatcher registers a WatcherLoader to the config.

func (*S) RunHooks Uses

func (c *S) RunHooks() error

RunHooks runs all hooks and child groups hooks

func (*S) Set Uses

func (c *S) Set(k string, v interface{})

Set sets a value in config

func (*S) SetLogger Uses

func (c *S) SetLogger(l nlogger.Structured)

SetLogger sets the logger used in the store

func (*S) Strict Uses

func (c *S) Strict(keys ...string) Store

Strict specifies mandatory keys on the konfig. After strict is called, konfig will wait for the first config Load to happen and will check if the specified strict keys are present, if not, Load will return a non nil error. Then, after every following `Load` of a loader, it will check if the strict keys are still present in the konfig and consider the load a failure if a key is not present anymore.

func (*S) String Uses

func (c *S) String(k string) string

String gets the config k and tries to convert it to a string It returns the zero value if it doesn't find the config.

func (*S) StringMap Uses

func (c *S) StringMap(k string) map[string]interface{}

StringMap gets the config k and converts it to a map[string]interface{}. it returns the zero value if it doesn't find the config.

func (*S) StringMapString Uses

func (c *S) StringMapString(k string) map[string]string

StringMapString gets the config k and converts it to a map[string]string. it returns the zero value if it doesn't find the config.

func (*S) StringSlice Uses

func (c *S) StringSlice(k string) []string

StringSlice gets the config k and converts it to a []string. It returns the zero value if it doesn't find the config.

func (*S) Time Uses

func (c *S) Time(k string) time.Time

Time gets the config k and converts it to a time.Time. It returns the zero value if it doesn't find the config.

func (*S) Value Uses

func (c *S) Value() interface{}

Value returns the value bound to the config store

func (*S) Watch Uses

func (c *S) Watch() error

Watch starts the watchers on loaders

type Store Uses

type Store interface {
    // Name returns the name of the store
    Name() string
    // SetLogger sets the logger within the store
    // it will propagate to all children groups
    SetLogger(l nlogger.Structured)
    // RegisterLoader registers a Loader in the store and adds the given loader hooks.
    RegisterLoader(l Loader, loaderHooks ...func(Store) error) *ConfigLoader
    // RegisterLoaderWatcher reigsters a LoaderWatcher in the store and adds the given loader hooks.
    RegisterLoaderWatcher(lw LoaderWatcher, loaderHooks ...func(Store) error) *ConfigLoader
    // RegisterCloser registers an io.Closer in the store. A closer closes when konfig fails to load configs.
    RegisterCloser(closer io.Closer) Store
    // RegisterKeyHook adds a hook to be run when the key changes.
    // If a key has the given key as path prefix, it runs the hook as well.
    RegisterKeyHook(k string, h func(Store) error) Store

    // Strict specifies mandatory keys on the konfig. When Strict is called, konfig will check that the specified keys are present, else it will return a non nil error.
    // Then, after every following `Load` of a loader, it will check if the strict keys are still present in the konfig and consider the load a failure if a key is not present anymore.
    Strict(...string) Store
    // RunHooks runs all hooks and child groups hooks
    RunHooks() error

    // Load loads all loaders registered in the store. If it faisl it returns a non nil error
    Load() error
    // Watch starts all watchers registered in the store. If it fails it returns a non nil error.
    Watch() error

    // LoadWatch loads all loaders registered in the store, then starts watching all
    // watchers. If loading or starting watchers fails, loadwatch stops and returns a non nil error.
    LoadWatch() error

    // Group lazyloads a child Store from the current store. If the group already exists, it just returns it, else it creates it and returns it. Groups are useful to namespace configs by domain.
    Group(g string) Store

    // Getter returns a GetterTyped for the given key k
    Getter(k string) ngetter.GetterTyped

    // Get gets the value with the key k fron the store. If the key is not set, Get returns nil. To check whether a value is really set, use Exists.
    Get(k string) interface{}
    // MustGet tries to get the value with the key k from the store. If the key k does not exist in the store, MustGet panics.
    MustGet(k string) interface{}
    // Set sets the key k with the value v in the store.
    Set(k string, v interface{})
    // Exists checks whether the key k is set in the store.
    Exists(k string) bool
    // MustString tries to get the value with the key k from the store and casts it to a string. If the key k does not exist in the store, MustGet panics.
    MustString(k string) string

    // String tries to get the value with the key k from the store and casts it to a string. If the key k does not exist it returns the Zero value.
    String(k string) string

    // MustInt tries to get the value with the key k from the store and casts it to a int. If the key k does not exist in the store, MustInt panics.
    MustInt(k string) int

    // Int tries to get the value with the key k from the store and casts it to a int. If the key k does not exist it returns the Zero value.
    Int(k string) int

    // MustFloat tries to get the value with the key k from the store and casts it to a float. If the key k does not exist in the store, MustFloat panics.
    MustFloat(k string) float64
    // Float tries to get the value with the key k from the store and casts it to a float. If the key k does not exist it returns the Zero value.
    Float(k string) float64

    // MustBool tries to get the value with the key k from the store and casts it to a bool. If the key k does not exist in the store, MustBool panics.
    MustBool(k string) bool
    // Bool tries to get the value with the key k from the store and casts it to a bool. If the key k does not exist it returns the Zero value.
    Bool(k string) bool

    // MustDuration tries to get the value with the key k from the store and casts it to a time.Duration. If the key k does not exist in the store, MustDuration panics.
    MustDuration(k string) time.Duration
    // Duration tries to get the value with the key k from the store and casts it to a time.Duration. If the key k does not exist it returns the Zero value.
    Duration(k string) time.Duration

    // MustTime tries to get the value with the key k from the store and casts it to a time.Time. If the key k does not exist in the store, MustTime panics.
    MustTime(k string) time.Time
    // Time tries to get the value with the key k from the store and casts it to a time.Time. If the key k does not exist it returns the Zero value.
    Time(k string) time.Time

    // MustStringSlice tries to get the value with the key k from the store and casts it to a []string. If the key k does not exist in the store, MustStringSlice panics.
    MustStringSlice(k string) []string
    // StringSlice tries to get the value with the key k from the store and casts it to a []string. If the key k does not exist it returns the Zero value.
    StringSlice(k string) []string

    // MustIntSlice tries to get the value with the key k from the store and casts it to a []int. If the key k does not exist in the store, MustIntSlice panics.
    MustIntSlice(k string) []int
    // IntSlice tries to get the value with the key k from the store and casts it to a []int. If the key k does not exist it returns the Zero value.
    IntSlice(k string) []int

    // MustStringMap tries to get the value with the key k from the store and casts it to a map[string]interface{}. If the key k does not exist in the store, MustStringMap panics.
    MustStringMap(k string) map[string]interface{}
    // StringMap tries to get the value with the key k from the store and casts it to a map[string]interface{}. If the key k does not exist it returns the Zero value.
    StringMap(k string) map[string]interface{}

    // MustStringMapString tries to get the value with the key k from the store and casts it to a map[string]string. If the key k does not exist in the store, MustStringMapString panics.
    MustStringMapString(k string) map[string]string
    // StringMapString tries to get the value with the key k from the store and casts it to a map[string]string. If the key k does not exist it returns the Zero value.
    StringMapString(k string) map[string]string

    // Bind binds a value (either a map[string]interface{} or a struct) to the config store. When config values are set on the config store, they are also set on the bound value.
    Bind(interface{})

    // BindStructStrict strictly binds a struct to the config store and add's the struct's exposed fields as strict keys.
    BindStructStrict(interface{})

    // Value returns the value bound to the config store.
    // It panics if no bound value has been set
    Value() interface{}
}

Store is the interface

func Group Uses

func Group(groupName string) Store

Group gets a group of configs

func Instance Uses

func Instance() Store

Instance returns the singleton global config store

func RegisterCloser Uses

func RegisterCloser(closer io.Closer) Store

RegisterCloser adds a closer to the list of closers. Closers are closed when an error occurred while reloading a config and the ExitOnError config is set to true

func RegisterKeyHook Uses

func RegisterKeyHook(k string, f func(Store) error) Store

RegisterKeyHook adds a hook to be run on the given key k and all subkeys of k

func Strict Uses

func Strict(keys ...string) Store

Strict specifies mandatory keys on the konfig. After strict is called, konfig will wait for the first config Load to happen and will check if the specified strict keys are present, if not, Load will return a non nil error. Then, after every following `Load` of a loader, it will check if the strict keys are still present in the konfig and consider the load a failure if a key is not present anymore.

type Values Uses

type Values map[string]interface{}

Values is the values attached to a loader

func (Values) Set Uses

func (x Values) Set(k string, v interface{})

Set adds a key value to the Values

type Watcher Uses

type Watcher interface {
    // Start starts the watcher, it must no be blocking.
    Start() error
    // Done indicate whether the watcher is done or not
    Done() <-chan struct{}
    // Watch should block until an event unlocks it
    Watch() <-chan struct{}
    // Close closes the watcher, it returns a non nil error if it is already closed
    // or something prevents it from closing properly.
    Close() error
    // Err returns the error attached to the watcher
    Err() error
}

Watcher is the interface implementing a config watcher. Config watcher trigger loaders. A file watcher or a simple Timer can be valid watchers.

Directories

PathSynopsis
loader/klconsul
loader/klenv
loader/kletcd
loader/klfile
loader/klflag
loader/klhttp
loader/klreader
loader/klvault
mocksPackage mocks is a generated GoMock package.
parser
parser/kpjson
parser/kpkeyvalPackage kpkeyval provides a key value parser to parse an io.Reader's content of key/values with a configurable separator and add it into a konfig.Store.
parser/kpmap
parser/kptoml
parser/kpyaml
watcher/kwfile
watcher/kwpoll

Package konfig imports 16 packages (graph) and is imported by 32 packages. Updated 2020-06-09. Refresh now. Tools for package owners.